Aller au contenu principal

Installer la CLI tale

Installe la CLI tale, choisis le bon environnement et retrouve les commandes de déploiement, de configuration et de maintenance.

44 min de lecture

La CLI tale permet d’installer Tale, de le déployer et d’en assurer l’exploitation. Installe-la sur la machine où tu exécuteras tes commandes, puis suis le démarrage rapide en local ou la procédure de déploiement ci-dessous.

La même CLI gère les opérations du workspace sur les conteneurs, les déploiements depuis des commits source exacts et les releases de configuration client. Ton automatisation choisit la destination, les références et les références d’identifiants, puis appelle la CLI. Publier les configurations d’un client traite les contenus conservés dans son propre repository.

Pour ta première instance, suis le démarrage rapide. Le parcours habituel est tale init, puis tale dev. Une spécification de déploiement géré n’est nécessaire que si ton automatisation doit fixer les commits source exacts du runtime et du client.

Avant de commencer

Il te faut :

  • Un ordinateur sous macOS, Linux ou Windows avec PowerShell.
  • Pour les conteneurs en local : Docker Engine 24.0 ou une version ultérieure avec Compose et un daemon Docker en cours d’exécution. Les couches des images Tale sont compressées en zstd, ce que Docker sait récupérer à partir d’Engine 23.0 ; tale doctor signale un moteur plus ancien, et tale dev comme tale deploy, déploiement d’un bundle compris, le refusent avant de télécharger les images.
  • Pour un workspace distant : l’accès à son daemon Docker, avec Docker Engine 24.0 ou une version ultérieure, généralement par un contexte Docker SSH. Le compte utilisé sur l’hôte distant doit pouvoir exécuter Docker.

Le stockage objet fourni n’existe actuellement qu’en image linux/amd64. Sur un hôte ARM64, le développement local et les déploiements de workspace nécessitent donc une émulation amd64 fonctionnelle : Docker Desktop l’inclut ; sur un hôte Linux avec Docker autonome, QEMU doit être enregistré sur l’hôte. Tale sélectionne l’image amd64, mais n’installe pas l’émulation. Les bundles de déploiement géré exigent toujours des images natives pour l’architecture déclarée. Un déploiement géré ARM64 doit donc attendre une image native du stockage objet.

L’installeur télécharge l’exécutable depuis GitHub. Il doit pouvoir joindre raw.githubusercontent.com, api.github.com, github.com et les destinations de téléchargement vers lesquelles GitHub le redirige.

Lancer install-cli.sh ou install-cli.ps1

Sur macOS ou Linux :

bash
curl -fsSL https://raw.githubusercontent.com/tale-project/tale/main/scripts/install-cli.sh | bash

Sur Windows PowerShell :

powershell
irm https://raw.githubusercontent.com/tale-project/tale/main/scripts/install-cli.ps1 | iex

L’installeur Unix choisit l’exécutable adapté au système et au processeur. Par défaut, il remplace un exécutable tale déjà présent dans le PATH, ou l’installe dans /usr/local/bin. Il demande sudo seulement si l’écriture dans ce répertoire le nécessite. Sous Windows, il utilise %LOCALAPPDATA%\Programs\tale par défaut et ajoute ce répertoire au PATH de ton compte.

Des exécutables sont disponibles pour macOS avec Apple Silicon ou Intel, Linux x86_64 ou arm64, et Windows x64. Windows ARM nécessite l’émulation x64. Si une architecture Unix n’est pas prise en charge, l’installeur indique comment compiler depuis les sources.

Définis VERSION pour choisir une version précise et INSTALL_DIR pour changer le répertoire de destination. Dans un shell Unix, exporte ces variables avant de lancer le pipeline pour que le processus bash les reçoive. Une affectation placée uniquement avant curl ne les transmet pas à l’installeur. Dans PowerShell, utilise $env:VERSION et $env:INSTALL_DIR.

OSScript d'installeur
macOSscripts/install-cli.sh
Linuxscripts/install-cli.sh
Windowsscripts/install-cli.ps1

Vérifier

bash
tale --version

La CLI affiche la version installée. Si la commande est introuvable, vérifie le répertoire indiqué par l’installeur et ajoute-le au PATH. Si un terminal Windows déjà ouvert ne trouve toujours pas tale, rouvre-le. Si le téléchargement échoue, vérifie l’accès aux destinations réseau ci-dessus. La variable d’environnement facultative GITHUB_TOKEN authentifie la recherche de version lorsque GitHub limite les appels anonymes à son API.

Vérifier la configuration

Pour les commandes qui gèrent les conteneurs, utilise le workspace créé avec tale init dans le démarrage rapide. La CLI recherche tale.json dans le répertoire courant puis dans ses parents. Vérifie le projet sélectionné avant de le modifier :

bash
tale config show

Les releases de configuration et les déploiements gérés désignent explicitement sources et destinations, sans s’aligner sur un workspace voisin. config show garde son comportement existant pour les projets locaux.

Pour un déploiement de workspace, l’hôte du proxy, les réglages TLS et les secrets vivent dans son .env. Pour la production, modifie HOST ou passe --host à tale deploy. En local, tale dev utilise localhost par défaut ; ses options --host et --port ne valent que pour cette exécution. Pour un workspace distant, utilise le contexte Docker de ton shell ou DOCKER_HOST. Un bundle géré s’applique sur la destination déclarée avec son daemon Docker local.

Lancer tale deploy

bash
tale deploy

Sans --bundle, tale deploy déploie la version de la CLI : il récupère ses images, redémarre les conteneurs concernés dans l’ordre prévu et exécute les migrations. Choisis auparavant une autre version de workspace avec tale update. Pour des commits source distincts du runtime et du client, suis Déploiements gérés.

Référence des commandes

La CLI regroupe ses commandes selon ce que tu fais, comme le fait tale --help. Chaque commande et ses arguments sont listés ci-dessous. Comment lire la notation :

  • Un argument positionnel entre [crochets] est optionnel ; entre <chevrons>, il est requis.
  • Les options obligatoires des releases de configuration sont indiquées explicitement ; les autres options sont facultatives, sauf indication contraire dans l’aide de la commande.
  • Une option de la forme --option <valeur> exige une valeur quand tu l'utilises (p. ex. --port 8443) ; une option seule comme --detach est un commutateur booléen.
  • Les valeurs par défaut figurent entre parenthèses après la description. Aucune valeur par défaut signifie que l'option est désactivée, ou que la valeur est résolue depuis .env / le contexte.

Cette référence décrit aussi les commandes du code source actuel. La CLI publiée en version v0.5.70 ne contient ni tale doctor ni tale dev --stop. Consulte tale --help et tale <commande> --help pour connaître les commandes et options disponibles dans ta version installée.

Les options globales fonctionnent sur chaque commande :

  • --verbose — sortie détaillée : logs de débogage et flux brut du sous-processus (forme longue uniquement ; il n'y a pas de -v).
  • -q, --quiet — uniquement les avertissements et les erreurs.
  • -y, --yes — répondre « oui » à toutes les questions (non interactif).
  • --no-color — désactiver les couleurs ANSI (respecte aussi NO_COLOR / FORCE_COLOR).
  • --json — JSON lisible par machine sur stdout ; pris en charge par doctor, status, sandbox status, toutes les sous-commandes config et les commandes de déploiement géré.
  • --ci — forcer une sortie non interactive en mode ajout seul (sans contrôle du curseur).

Les commandes se terminent avec 0 en cas de succès, 2 pour une erreur d'utilisation, 3 pour une condition préalable non remplie (pas de projet, Docker arrêté, port occupé), 4 pour une interruption par l'utilisateur (Ctrl-C, ou une question requise sans terminal) et 5 pour l'échec d'une dépendance externe — ainsi les scripts peuvent se ramifier selon la cause.

Installation

tale doctor — examine les prérequis d’un démarrage local sans créer de projet, installer de logiciel ni modifier la configuration. La commande vérifie le daemon Docker, la version de Docker Engine, la prise en charge de Compose et le mode de conteneurs Linux, indique l’architecture du daemon et examine les ports locaux. Avec un contexte Docker distant, elle ignore les ports locaux. Examine les avertissements sur ARM64 et les ports occupés ; une instance existante peut déjà utiliser le port.

  • -p, --port <port> — port HTTPS à vérifier (par défaut 443) ; le port sandbox 8003 est aussi vérifié.
  • --json — produit les résultats en JSON lisible par machine.

Un échec lié à Docker, Compose, à un Docker Engine antérieur à la version 24.0, à un mode de conteneurs non pris en charge ou au choix du port HTTPS 8003 renvoie le code 3. Les avertissements seuls renvoient 0 ; cela ne vérifie ni les téléchargements d’images, ni la capacité de stockage, ni le fournisseur de modèles. Vérifie un autre port avec tale doctor --port 8443, puis utilise le même port avec tale dev.

tale init [directory] — créer un projet : crée les configs d'exemple, AGENTS.md + un pointeur CLAUDE.md et un .env local par défaut (localhost, certificat auto-signé, secrets générés). Aucun Docker requis ; le domaine de production et le TLS sont choisis plus tard, lors de tale deploy. Dans un terminal, il demande un nom de projet quand directory est omis, confirme avant d'écraser un projet existant, et demande une fois si les agents peuvent lancer docker dans les sandboxes (par défaut : non — l'activer fait tourner un Docker interne privilégié) ; les exécutions non interactives sautent toutes les questions. directory est optionnel (par défaut : le répertoire courant).

  • -f, --force — écraser un tale.json existant au lieu d'abandonner.
  • --no-env — créer le projet mais ignorer la génération du .env.

tale dev — démarrer tous les services localement avec un certificat auto-signé. L’hôte et le port choisis définissent l’adresse locale de l’application pour cette exécution, sans réécrire les réglages de production dans .env. La vérification attend que les services dotés de sondes de santé soient sains et que les autres soient en cours d’exécution. Si le délai est dépassé, consulte les logs des services signalés avant de réessayer.

  • -d, --detach — s'exécuter en arrière-plan au lieu de diffuser les logs.
  • --stop — arrête les conteneurs locaux de développement de ce projet et conserve leurs données. Relance tale dev pour reprendre.
  • -p, --port <port> — port HTTPS à exposer (par défaut 443).
  • --host <hostname> — alias d'hôte pour le proxy (par défaut localhost).
  • -y, --yes — non-interactif : accepter automatiquement les invites (p. ex. installer ou démarrer Docker).

tale deploy — déployer la version de la CLI avec remplacement blue-green des rôles applicatifs. Les services d’exécution partagés sont remplacés sur place ; la base et le proxy nécessitent --stop. Au premier déploiement, la CLI demande domaine public et e-mail TLS s’ils ne sont pas fournis. Consulte Mises à jour avant de modifier une installation existante.

  • --stop — mettre aussi à jour le palier arrêté-puis-recréé (db, proxy) — ces conteneurs sont recréés, donc accepte une brève interruption ; sans l'option, les db/proxy en marche restent intouchés.
  • -s, --services <list> — ne mettre à jour que ces services séparés par des virgules (par défaut : tous les services rotatifs).
  • --host <hostname> — alias d'hôte pour le proxy (par défaut : la valeur HOST de .env).
  • --override — écraser la config du conteneur depuis le workspace local (les *.secrets.json chiffrés et .history/ sont toujours préservés).
  • --override-all — réinitialiser le catalogue intégré dans chaque organisation côté serveur ; implique --stop.
  • -q, --quiet — masquer les logs des conteneurs pendant le déploiement.
  • -y, --yes — accepter automatiquement les confirmations destructives (p. ex. --override-all).
  • --skip-backup — ignorer le snapshot de volume automatique d'avant déploiement.
  • --configuration-only — applique uniquement la configuration gérée à chaud (instructions, autorisations d’outils des agents et automatisations) au runtime sain exact d’un déploiement déjà prêt. Exige --bundle <directory> et saute le snapshot préalable au déploiement ainsi que le redémarrage. Utilise cette option quand seules ces ressources changent ; les paramètres du runtime et de l’identité doivent rester inchangés, sans déploiement du runtime en attente.
  • --dry-run — prévisualiser sans rien modifier.

Déploiements gérés

Utilise une déclaration de déploiement vérifiée quand le runtime et les configurations client doivent suivre des commits source exacts. Ton automatisation choisit la destination, les identifiants et les références, puis appelle la CLI Tale. Celle-ci acquiert les sources, résout et vérifie les digests des images, prépare le transfert, préserve l’état existant pris en charge, crée les snapshots de récupération nécessaires, déploie la stack, provisionne l’instance native et vérifie la configuration. Cette logique de déploiement reste dans Tale.

Préparer le runtime et les références source

Lance la préparation sous Linux avec une CLI compilée depuis un checkout Tale propre et committé, pour l’architecture cible linux/amd64 ou linux/arm64. Le même exécutable accompagne le paquet pour le provisionnement local au backend. La préparation demande Git et Docker pour vérifier sources et images. L’application s’exécute sur la destination avec son daemon Docker local, son répertoire d’état conservé et son environnement. Le commit complet de CLI, le commit source du runtime et celui de la configuration client sont trois références distinctes. Sur la destination, le runtime préparé ne publie que les ports 80 et 443 du proxy et les deux bases de données sur 127.0.0.1:5432 et 127.0.0.1:5433 ; le spawner sandbox (8003) et son hub d’appareils (8004) restent sur le réseau interne, où le backend et le proxy les joignent.

Un déploiement géré consigne son point de récupération avant de modifier quoi que ce soit : le snapshot pris avant le déploiement et le bundle en cours d’application, conservés dans le répertoire d’état jusqu’à l’écriture du reçu ready. Un déploiement interrompu attend donc le même bundle à la reprise et en refuse un autre, en nommant le sha256 du bundle en attente. Quand ce bundle ne peut plus aboutir — parce qu’une CLI corrigée est désormais épinglée, par exemple —, déclare le sha256 nommé comme supersedesPendingBundle dans la déclaration de déploiement et relance la préparation : le bundle vérifié reprend le même snapshot, le reçu ready le liste sous supersededBundles, et tu retires ensuite la déclaration. Cette reprise couvre le point de récupération du déploiement, pas le déploiement du runtime lui-même. Un déploiement du runtime arrêté après la vérification de ses images — au démarrage de Compose ou pendant l’attente des contrôles de santé — ne reprend qu’avec le même runtime préparé (runtime/runtime.json), la même origine, les mêmes réglages TLS et le même environnement ; il refuse un bundle dont le runtime ou les réglages diffèrent, avec ou sans supersedesPendingBundle, par A different runtime operation is pending; recover that exact operation first. Termine-le avec le bundle qui l’a lancé avant de changer la CLI épinglée, dans un sens comme dans l’autre : une autre CLI peut préparer un runtime différent à partir du même commit de runtime. Les phases locales au backend (deploy provision, deploy export-client-native) s’exécutent dans le backend sous son propre utilisateur, propriétaire de son répertoire de données ; quand l’une échoue, le résultat du déploiement reprend le résumé de la CLI interne.

Le snapshot pris avant le déploiement contient aussi le stockage de la passerelle de modèles, llm-gateway-data, qu’une passerelle plus récente migre sans retour possible dès son premier démarrage sur ce stockage. Un déploiement en attente qui n’a rien modifié ne consigne aucun snapshot ; une reprise par supersedesPendingBundle, ou une nouvelle tentative qui modifie le runtime, prend d’abord le snapshot et le consigne avec le déploiement en attente. Un point de récupération sans le stockage de la passerelle (un snapshot pris avant que la CLI capture ce stockage, ou aucun après une reprise par une CLI plus ancienne) bloque tout déploiement qui démarrerait une image de passerelle que ce stockage n’a jamais fait tourner d’après le reçu du runtime et le conteneur de la passerelle : l’application du bundle est refusée avant toute modification et le reçu en attente reste tel quel, car un snapshot pris maintenant pourrait déjà contenir un stockage migré. Ne supprime pas le reçu. Tant qu’aucun déploiement du runtime n’est en attente, un bundle vérifié qui résout encore l’image de passerelle exécutée en dernier par le déploiement peut le reprendre avec supersedesPendingBundle ; le déploiement suivant prend un snapshot qui contient le stockage de la passerelle. Dès qu’un déploiement du runtime est en attente, la CLI n’offre aucune issue pour cet état. Un déploiement sur une image de passerelle déjà exécutée sur ce stockage aboutit, et signale quand son snapshot ne contient pas le stockage ou qu’il n’a aucun point de récupération. Un déploiement géré ne revient jamais en arrière de lui-même et ne restaure aucun volume ; il conserve son état en attente pour la récupération.

Les commandes de bundle géré ne sont pas disponibles sous Windows, y compris deploy verify-bundle et le deploy provision local au backend : leurs contrôles d’intégrité exigent les droits d’exécution POSIX. Exécute le déploiement géré complet sur un hôte Linux. Les commandes ordinaires du workspace et les commandes autonomes config build, verify, stage, deploy et verify-native restent disponibles sous Windows.

Cet exemple synthétique cible une organisation et un projet existants. Remplace les ID publics et définis les variables nommées. revision accepte un SHA de commit complet ou une référence d’environnement. Les identifiants restent des références, résolues en privé sur la destination. tlsMode: "external" suppose qu’un point d’entrée existant gère le TLS public ; letsencrypt demande aussi tlsEmail.

Pour les jobs Linux ou macOS ARM64 de GitHub Actions, utilise l’action composite Tale .github/actions/setup-cli. Fixe l’action et revision au même commit Tale complet. Elle compile avec Bun 1.4.2, vérifie le binaire final, fournit executable et complète le PATH. Les builds macOS prennent en charge la préparation générale de configuration ; la pile Linux gérée exige toujours un binaire Linux correspondant. Sur un runner Linux x64, passe linux-baseline: 'true' quand le processeur cible n’a pas AVX2 (Intel avant Haswell, par exemple). Le binaire standard s’y arrête sur Illegal instruction, le binaire baseline fonctionne. Les autres runners refusent cette option.

origin et chaque entrée native redirectUris acceptent aussi des références d’environnement. Un registre de déploiement peut ainsi posséder les adresses publiques. La préparation les résout en URL HTTPS littérales validées dans le bundle.

L’exemple définit runtime.containerPrefix pour rendre l’environnement reconnaissable dans la liste des conteneurs. Cette option est expliquée ci-dessous.

json
{
  "schemaVersion": 1,
  "name": "example-native",
  "stateDirectory": "/opt/tale-example",
  "composeProject": "tale-example",
  "runtime": {
    "revision": { "env": "TALE_RUNTIME_REF" },
    "platform": "linux/amd64",
    "containerPrefix": "north-desk-prod"
  },
  "origin": { "env": "TALE_PUBLIC_ORIGIN" },
  "tlsMode": "external",
  "identity": {
    "email": { "env": "EXAMPLE_OPERATOR_EMAIL" },
    "password": { "env": "EXAMPLE_OPERATOR_PASSWORD" },
    "slug": "example-team",
    "name": "Example team",
    "ssoEnabled": false,
    "nativeClients": [
      {
        "key": "example-portal",
        "name": "Example portal",
        "clientId": { "env": "EXAMPLE_NATIVE_CLIENT_ID" },
        "redirectUris": [{ "env": "EXAMPLE_PORTAL_CALLBACK" }]
      }
    ]
  },
  "configs": [
    {
      "repository": "https://github.com/example-team/client-app",
      "revision": { "env": "EXAMPLE_CONFIG_REF" },
      "client": "example-team",
      "descriptor": "tale/client.json",
      "automation": "document-review",
      "projectId": "existing-project-id",
      "skillOwner": "native-operator-id"
    }
  ]
}

Choisir l’environnement des rapports d’erreurs

Les instances gérées définissent SENTRY_ENVIRONMENT sur le name existant du déploiement par défaut. Pour utiliser un libellé canonique comme example-pr, déclare "environment": { "SENTRY_ENVIRONMENT": { "env": "TALE_REPORTING_ENVIRONMENT" } } et définis cette variable à destination. Le libellé commence par une lettre minuscule ou un chiffre et contient de 1 à 64 lettres minuscules, chiffres ou traits d’union. Le navigateur, le backend et la sandbox l’utilisent sans modifier name, composeProject, stateDirectory ni les identifiants enregistrés.

Choisir les noms des conteneurs

Définis runtime.containerPrefix pour obtenir des noms comme north-desk-prod-db et north-desk-prod-backend-api dans la liste des conteneurs. Le préfixe commence par une lettre minuscule et contient des lettres minuscules, des chiffres et des traits d’union simples, sur 40 caractères au maximum. Les espaces, les traits de soulignement, les traits d’union répétés et un trait d’union final sont refusés.

ParamètreCe qu’il identifie
runtime.containerPrefixLe nom visible de chaque conteneur géré : <prefix>-<service>.
name et composeProjectLe déploiement existant et son projet Compose, y compris l’appartenance des volumes.
stateDirectoryL’état du déploiement, les identifiants et les traces nécessaires à la reprise.

Garde les valeurs des deux dernières lignes lorsque tu renommes les conteneurs d’une installation existante. Le préfixe ne modifie pas les noms DNS des services : leurs adresses internes conservent donc les mêmes noms. Sans préfixe, la convention de nommage du code source s’applique.

Ajouter, modifier ou retirer un préfixe recrée les conteneurs et peut interrompre brièvement le service. Prépare un nouveau bundle, examine sa simulation, puis applique-le en suivant la procédure habituelle de snapshot et de reprise. Si l’application est interrompue, relance exactement ce bundle ; un déploiement en attente refuse un autre bundle. Une fois le déploiement terminé, tu peux retirer le préfixe avec un autre bundle préparé pour rétablir la convention du code source.

Exécute une seule instance gérée complète par démon Docker. Un préfixe de nom n’attribue pas de ports, de réseaux sandbox ou de répertoires de travail distincts sur l’hôte.

Servir des origines supplémentaires

Déclare additionalOrigins lorsque la même instance doit aussi répondre sur d’autres origines HTTPS, par exemple un domaine partenaire ou l’ancien nom d’hôte pendant un déménagement. Chaque entrée est une origine HTTPS nue sur le port par défaut, ou une référence d’environnement que la préparation résout en une telle origine. La liste compte de 1 à 16 origines distinctes ; aucune ne peut reprendre origin.

json
{
  "origin": "https://desk.example.org",
  "additionalOrigins": [
    "https://desk.partner.example",
    { "env": "TALE_EXTRA_ORIGIN" }
  ]
}

La CLI écrit la liste dans la variable ADDITIONAL_SITE_URLS du runtime et la gère elle-même : une entrée de environment ne peut donc pas la définir. Chaque origine est un point d’entrée complet, avec ses propres sessions, liens de fichiers, accès de connexion et callbacks de connectors. Avec tlsMode: "letsencrypt", le proxy obtient un certificat pour chaque origine, et les noms d’hôte locaux ou les adresses IP sont refusés. Avec tlsMode: "external", ton proxy TLS doit transmettre l’en-tête Host d’origine de chaque origine et envoyer X-Forwarded-Proto: https depuis une adresse à laquelle le proxy de Tale fait confiance. Si cette plage est plus étroite que les plages d’adresses privées, définis TRUSTED_PROXIES par une référence dans environment.

L’identité native reste sur origin : les liaisons du compte et de l’organisation, les journaux des clients, l’émetteur OIDC, les passkeys et les liens envoyés par e-mail n’utilisent que celle-ci. Une entrée peut être égale à identity.migrateOriginFrom pour que l’ancien nom d’hôte continue de répondre pendant une migration.

La préparation refuse une révision du runtime dont le proxy ne peut pas faire confiance à un terminateur TLS externe, avec le message Runtime does not serve additional origins. Ajouter, modifier ou retirer la liste recrée les services qui la lisent. Une fois la déclaration retirée, le bundle appliqué suivant supprime aussi la variable. Enregistre les URL de callback de chaque origine auprès de tes fournisseurs d’identité et de connectors, et prépare le DNS et les certificats avec TLS et domaines.

Désigner qui peut créer des organisations

Un déploiement géré refuse la création d’organisations à son proxy pour tout le monde : le choix d’organisation n’affiche pas d’entrée Créer une organisation, et POST /api/auth/organization/create répond 403. Pour que des personnes désignées puissent ouvrir d’autres espaces de travail, déclare organizations.creators — de 1 à 64 adresses de connexion distinctes, littérales ou sous forme de références d’environnement que la préparation résout.

json
{
  "organizations": {
    "creators": ["ops@example.org", { "env": "TALE_WORKSPACE_LEAD" }]
  }
}

La CLI écrit la liste dans la variable TALE_ORGANIZATION_CREATORS du runtime et la gère elle-même : une entrée de environment ne peut donc pas la définir. Une fois la déclaration en place, le proxy ne refuse plus la création d’organisations ; c’est le backend qui compare chaque personne à la liste, répond 403 ORGANIZATION_CREATION_FORBIDDEN à toutes les autres, et l’application n’affiche Créer une organisation qu’aux personnes désignées. Les adresses sont comparées sans tenir compte de la casse ; deux graphies d’une même adresse sont refusées comme doublon.

L’organisation gérée elle-même n’est pas concernée : le déploiement la crée pendant le bootstrap, et la première organisation d’un déploiement est toujours autorisée. Retire la déclaration et applique le bundle suivant pour rétablir le refus au proxy et supprimer la variable. La même variable fonctionne sur un déploiement que tu exploites toi-même ; voir la référence des variables d’environnement.

Préparer, vérifier et appliquer le bundle

Définis TALE_DEPLOY_SPEC avec ce fichier JSON, TALE_DEPLOY_BUNDLE avec un nouveau répertoire absolu et TALE_CLI_COMMIT avec le commit complet du binaire. DEPLOYMENT_COMMIT est une provenance d’orchestration optionnelle ; omets ses arguments si tu ne l’utilises pas. Prépare et vérifie, transfère le répertoire entier, puis lance l’aperçu et le déploiement sur la destination avec la même CLI fixée.

bash
tale --json deploy prepare \
  --spec "$TALE_DEPLOY_SPEC" \
  --deployment-ref "$DEPLOYMENT_COMMIT" \
  --output "$TALE_DEPLOY_BUNDLE"

tale --json deploy verify-bundle \
  --bundle "$TALE_DEPLOY_BUNDLE" \
  --cli-ref "$TALE_CLI_COMMIT" \
  --deployment-ref "$DEPLOYMENT_COMMIT"

tale --json deploy --bundle "$TALE_DEPLOY_BUNDLE" \
  --cli-ref "$TALE_CLI_COMMIT" \
  --deployment-ref "$DEPLOYMENT_COMMIT" --dry-run

tale --json --yes deploy --bundle "$TALE_DEPLOY_BUNDLE" \
  --cli-ref "$TALE_CLI_COMMIT" \
  --deployment-ref "$DEPLOYMENT_COMMIT"

deploy prepare accepte --sources-file <file> pour associer repository@fullSHA à des checkouts exacts existants. Sinon, la CLI récupère des repositories GitHub canoniques. Injecte le contenu d’une clé SSH en lecture seule pour les repositories client privés dans TALE_SOURCE_SSH_KEY, uniquement pendant la préparation. La CLI vérifie les clés d’hôte SSH de GitHub par HTTPS et garde la clé hors du paquet et du runtime. Docker doit déjà avoir accès au registre.

La préparation vérifie d’abord chaque configuration avec les schémas propres à la CLI, et seulement ensuite télécharge et vérifie les images du runtime. Elle nomme chaque phase et chaque image au fur et à mesure. Un paquet qui déclare des champs inconnus de cette CLI est refusé en quelques secondes avec native manifest normalization changes release semantics at <fields> ; prépare-le alors avec une CLI au moins aussi récente que le Tale visé par le paquet. Une erreur que la CLI lève délibérément affiche sa propre cause. Toute autre erreur garde un résumé fixe, afin qu’aucun identifiant ni aucune sortie du registre n’atteigne le journal.

deploy verify-bundle vérifie l’inventaire complet et les hashes sans contacter la destination. deploy --bundle --dry-run vérifie les artefacts de configuration et les préconditions de la destination sans appliquer de changement. Les déploiements gérés refusent les options réservées au workspace comme --services, --host ou --override-all. Ils déploient la stack en préservant son état, avec des contrôles de santé et de provenance. Le comportement blue-green du workspace décrit plus haut est un autre parcours.

Vérifier le déploiement actuel

Une fois ce bundle exact entièrement appliqué, recueille une preuve d’acceptation actuelle sur l’hôte du déploiement :

bash
tale --json deploy accept --bundle "$TALE_DEPLOY_BUNDLE" \
  --cli-ref "$TALE_CLI_COMMIT" --deployment-ref "$DEPLOYMENT_COMMIT" \
  --expected-version "$TALE_RELEASE_VERSION"

Cette vérification exige les deux commits sources complets ; le bundle doit avoir été préparé avec --deployment-ref. Définis TALE_RELEASE_VERSION sur la version publiée sélectionnée indépendamment, sans son préfixe v. La CLI prend le verrou de déploiement existant et lit le reçu Ready, les conteneurs actuels, les images fixées et les trois registres de migrations. Elle compare /api/health du frontend et /api/health/ready de l’API à l’origine HTTPS canonique avec les identités de processus lues directement dans les conteneurs locaux capturés, puis relit ces identités. Une identité absente ou un autre processus serveur entraîne un refus, même à version égale. La version OCI et le commit source de chaque image Tale doivent correspondre au bundle. sourceTag peut valoir sha-<source> : il décrit la référence de l’image, pas la version servie.

Le résultat JSON contient les commits sources, les hashes du bundle et du reçu Ready, les identités des images, l’origine canonique, les deux identités de processus serveur et l’inventaire complet des migrations issues du source, avec ses hashes. Il comprend les migrations SQL de l’application et les migrations de données TypeScript numérotées. Toute migration manquante, supplémentaire, dupliquée ou inachevée, tout déploiement en cours et tout changement de version ou d’identité entraînent un refus. Ces identités publiques relient un conteneur local à une réponse de l’origine ; ce ne sont ni des identifiants d’accès ni une preuve d’authentification.

Les observations Docker et HTTPS ont chacune une limite d’annulation et partagent un budget de 120 secondes écoulées, vérifié aux limites des observations. La vérification du bundle, sa copie temporaire privée et son nettoyage respectent les limites de taille existantes (2 GiB au total, 256 MiB par fichier) ; les attentes du système de fichiers ne sont pas couvertes par un délai annulable pour toute la commande. Utilise un superviseur de processus externe si tu as besoin d’un délai global. Cette vérification n’applique aucune configuration, ne redémarre aucun conteneur, n’exécute aucune migration et n’exporte aucun identifiant d’accès. Elle modifie les métadonnées du verrou, crée sa copie temporaire privée du bundle, puis la supprime.

Les anciens bundles restent déployables, mais cette vérification exige un inventaire des migrations issu du source et des serveurs compatibles qui publient leur identité de processus. Prépare un bundle vérifié et termine son déploiement par le parcours habituel avant de recueillir son reçu d’acceptation. Le reçu atteste l’état observé à son horodatage ; il ne garantit pas le routage ni l’état ultérieur des serveurs. Relance la vérification quand il te faut des preuves actuelles.

Observer l’état conservé avant un déploiement

tale --json deploy observe --spec <file> --cli-ref <sha> --deployment-ref <sha> --machine-id-sha256 <digest> recueille les identités des images en service, les inventaires de migrations, les métadonnées du corpus et de l’espace disque, ainsi que les preuves de configuration native conservées. Exécute la CLI compilée à la révision fixée sur l’hôte Linux vérifié, avec son socket Docker local. Fournis le JSON privé sur stdin sous la forme {"environment":{"UPPERCASE_ENV_NAME":"value"}}, avec uniquement les variables nécessaires à la spécification examinée. Les variables ambiantes ne servent pas de recours. L’entrée est limitée à 64 KiB, 128 clés et 8192 octets par valeur.

La commande réutilise les identifiants existants et les IDs exacts du compte et de l’organisation conservés. Elle lit les fichiers des packs sans les recompiler, vérifie les versions natives actuelles, les fichiers et les propriétaires des skills inclus, puis contrôle à nouveau l’état des fichiers et l’identité des conteneurs. Elle crée uniquement des fichiers temporaires et des sessions d’authentification, puis supprime ces fichiers et ferme les sessions. Elle ne crée aucune identité, ne prépare ni n’applique de configuration, ne migre rien, ne redémarre rien, ne purge aucune ressource et ne prend pas le verrou de bascule. Les lectures Docker et natives sont limitées ; supervise le processus extérieurement pour borner aussi les attentes du système de fichiers.

Une observation complète renvoie ok:true et data.complete:true. Si les preuves anciennes d’état ou de propriété manquent, le rapport conserve les faits disponibles sur l’hôte et les bases avec ok:false, data.complete:false, un code de motif prédéfini et le code de sortie 3. Garde ce rapport pour l’enquête. Une entrée invalide, des identités différentes ou un état modifié font refuser l’observation. Aucun résultat ne constitue une acceptation Ready, une autorisation de bascule ou une preuve que les packs survivront à un futur déploiement. Utilise le processus normal de déploiement examiné et d’acceptation pour ces décisions.

Configurer l’identité native

deploy provision [--bundle <directory>] est la phase locale au backend du déploiement du bundle. Elle lit au maximum 64 KiB de JSON privé sur stdin, vérifie le compte local et l’organisation sélectionnée, puis ferme la session avant d’annoncer le succès. Ses champs comprennent origin, email, password, slug, name, ssoEnabled, les identifiants Entra optionnels et nativeClients. Par défaut, le compte existant reste requis. Un identity.bootstrap: "fresh" explicite autorise la création du premier compte local et de l’organisation. Un bundle lie ce choix et les configurations préparées avant toute modification native. deploy provision refuse les options de workspace et --dry-run ; utilise les vérifications en lecture seule. Les attentes optionnelles --cli-ref et --deployment-ref exigent --bundle et sont contrôlées avant connexion.

Le déploiement du bundle appelle deploy provision avec des options internes pour les mises à jour de configuration seules et la vérification des identités conservées ; utilise tale deploy --bundle <directory> --configuration-only pour ce parcours opérateur.

Pour un nouvel opérateur vérifié administrativement, déclare explicitement identity.emailVerification: "operator-attested". Tu attestes ainsi la possession de l’adresse du compte authentifié ; ce n’est pas une preuve de livraison dans la boîte mail. Le backend utilise un jeton natif bref lié à ce compte et à cette adresse exacte, en conservant les hooks natifs. Il n’envoie aucun email, ne change pas l’adresse et ne crée pas d’autre session. Cette option exige bootstrap: "fresh". Sans elle, la vérification native habituelle reste inchangée. Une dérive du statut vérifié d’un compte précédemment prêt bloque pour examen.

Pour une nouvelle cible, remplace le projectId d’une configuration par project: { "key": "NORTH", "name": "Configuration" }. Une clé de projet natif compte 2–6 lettres majuscules, son nom au plus 80 caractères. skillOwner: "operator" transfère une capsule source vérifiée et la compile dans le backend pour l’utilisateur natif authentifié ; l’hôte vérifie indépendamment l’artefact obtenu. Les ID explicites existants et les versions déjà liées à leur propriétaire conservent leur comportement.

Chaque client natif choisit un clientId existant ou managed: true explicite. Avant la création native, la CLI conserve une intention privée, puis renvoie seulement un chemin privé de transmission et le SHA des identifiants. Les répétitions gardent ID, politique de sécurité et secrets. Une acceptation incertaine sans objet natif correspondant bloque. Pour les clients existants, seuls le nom affiché et les URL de callback HTTPS peuvent converger. Sur les backends 0.5 pris en charge, les créations ou modifications nécessaires utilisent des adaptateurs d’authentification locaux fixes, dont les connexions sont ensuite fermées. Cela n’ouvre aucune route publique d’inscription ou de modification, aucun chemin de module arbitraire et aucune rotation de secret.

Changer le nom d’hôte d’un déploiement géré

Utilise le déploiement géré existant et son répertoire d’état privé. Ce parcours modifie l’origine associée au compte, à l’organisation et aux clients existants ; il ne déplace pas la base de données et ne crée pas de nouvelles identités.

  1. Définis la nouvelle origine HTTPS dans origin de la spécification et l’origine HTTPS précédente exacte dans identity.migrateOriginFrom, par exemple https://old.example.org. Elles doivent être différentes. Conserve identity.bootstrap: "fresh", le compte, l’organisation et les clés des clients gérés.
  2. Vérifie l’état conservé avant de préparer le bundle. L’initialisation doit être terminée. Chaque attestation d’e-mail déclarée et chaque client géré nécessitent leur journal correspondant terminé. Un journal d’identité ou de client absent, en attente ou sans rapport avec la cible bloque la migration.
  3. Prépare et vérifie le bundle, examine l’aperçu, puis applique-le avec le parcours décrit plus haut. La CLI authentifie le compte existant et vérifie les identifiants client avant de modifier les origines associées. Une nouvelle tentative accepte les journaux terminés sur l’une ou l’autre origine déclarée, en conservant les IDs et les secrets.
  4. Une fois le reçu de déploiement prêt, exporte la configuration des applications clientes pour le nouvel émetteur. Retire migrateOriginFrom des prochaines spécifications de déploiement.

Si une configuration native est déclarée, son reçu conservé est également nécessaire. La migration garde l’ID et le slug de l’organisation et vérifie chaque ressource avec le parcours habituel de planification et de relecture. Une écriture de configuration interrompue sur la nouvelle origine reprend uniquement son plan exact en attente. Un reçu de configuration en attente sur l’ancienne origine bloque la migration.

Pour revenir en arrière après une migration terminée, inverse explicitement les deux origines et reprends le même parcours vérifié. Prépare le DNS, les certificats, les URL de rappel et les tests d’accès avec TLS et domaines. Changer l’origine dans le bundle n’effectue pas ces opérations externes.

Renommer l’adresse de l’opérateur de déploiement

Un déploiement géré se connecte à chaque exécution en tant qu’opérateur identity. Pour donner à ce compte une adresse machine, afin que les personnes se connectent avec leurs propres comptes, conserve le compte et ne change que son adresse de connexion. Son identifiant utilisateur, et tout ce qui en dépend — clients gérés, skills appartenant à l’opérateur, clés d’API et journaux conservés —, reste inchangé.

  1. Définis identity.email sur la nouvelle adresse et identity.migrateEmailFrom sur l’adresse précédente exacte. Les deux doivent être différentes. Conserve identity.bootstrap: "fresh" et le mot de passe du compte. Le bootstrap doit être terminé, et une attestation d’e-mail déclarée a besoin de son journal terminé.
  2. Prépare, vérifie, prévisualise et applique le bundle. La CLI lit l’adresse actuelle du compte conservé dans le backend, se connecte avec elle et prouve l’identifiant utilisateur conservé. Elle consigne le changement dans le journal, renomme le compte via l’adaptateur natif, met fin à toutes les sessions du compte et se reconnecte avec la nouvelle adresse. Le renommage est conditionné à l’adresse précédente : un changement concurrent est refusé au lieu d’être écrasé. Une attestation d’e-mail déclarée vérifie ensuite la nouvelle adresse.
  3. Une nouvelle tentative après une interruption trouve l’adresse déjà changée et termine les journaux sans second renommage. Laisser migrateEmailFrom déclaré ensuite est sans effet ; retire-le une fois le reçu de déploiement prêt.

Si un autre compte détient la nouvelle adresse, si le compte conservé ne détient aucune des deux adresses, ou si le compte de l’opérateur porte un lien d’authentification unique (SSO), le déploiement s’arrête avant toute modification. Retire d’abord un tel lien : il appartient à la personne qui s’est connectée avec, pas à un compte machine.

Déclarer un administrateur de secours

identity.breakGlass conserve un administrateur pour le cas où l’opérateur de déploiement est indisponible, par exemple { "email": "break-glass@example.org", "passwordHash": { "env": "TALE_BREAK_GLASS_PASSWORD_HASH" } }. L’adresse est une valeur littérale ou une référence d’environnement obligatoire, et doit différer de l’adresse actuelle et de l’adresse précédente de l’opérateur. Le mot de passe n’atteint jamais le déploiement : crée son hachage avec tale auth hash-password là où le mot de passe est conservé, et ne fournis que le hachage.

Chaque déploiement aligne le backend sur la déclaration. Un compte absent est créé avec une adresse vérifiée et exactement les identifiants déclarés, et un journal conservé lie l’adresse à son identifiant de compte dès que le compte existe. Les déploiements suivants rétablissent les identifiants déclarés sur le compte lié et mettent fin à toutes ses sessions dès que ces identifiants changent, y compris lorsqu’ils terminent une exécution interrompue. Un compte à cette adresse que ce déploiement n’a pas créé, ou plus tard un autre compte qui la détient, arrête le déploiement. Le compte devient admin de l’organisation gérée via les points d’accès natifs des membres ; un owner n’est jamais modifié. Le déploiement ne se connecte jamais avec ce compte. Change son mot de passe en modifiant le hachage déclaré, pas dans l’application. Le déploiement n’enregistre aucune date de changement de mot de passe : une politique de rotation des mots de passe de l’organisation peut donc demander un nouveau mot de passe à ce compte, que le déploiement suivant rétablit.

Connexion à deux facteurs imposée

Un déploiement géré se connecte en tant qu’opérateur avec le seul mot de passe. Si l’organisation impose two_factor_policy, donne à l’opérateur un passkey et jamais d’application d’authentification : la connexion par mot de passe d’un compte doté d’une application d’authentification reçoit une demande de code, et un compte sans aucun des deux facteurs est renvoyé vers la configuration à la fin de sa période de grâce. La CLI s’arrête à l’une ou l’autre réponse et nomme celle qu’elle a reçue. Les personnes se connectent avec leurs propres comptes et peuvent utiliser l’un ou l’autre facteur.

Exporter les identifiants des clients natifs

Pour transmettre les identifiants d’un client géré à une application distincte, définis NATIVE_CLIENT_KEY avec sa clé déclarée et PRIVATE_EXPORT_DIRECTORY avec un nouveau répertoire privé. Son répertoire parent doit déjà appartenir à ton compte, avoir le mode 0700 et se trouver sous des répertoires de confiance. Exporte depuis le même déploiement prêt, sans interpréter les chemins du backend ni les noms de conteneurs :

bash
tale --json deploy export-client --bundle "$TALE_DEPLOY_BUNDLE" \
  --client "$NATIVE_CLIENT_KEY" --output "$PRIVATE_EXPORT_DIRECTORY" \
  --env-prefix TALE_OIDC --cli-ref "$TALE_CLI_COMMIT" \
  --deployment-ref "$DEPLOYMENT_COMMIT"

Le répertoire de sortie a le mode 0700. Ses fichiers réguliers client.json, receipt.json et, avec --env-prefix, consumer-env.json ont le mode 0600. Le dernier contient quatre chaînes littérales : TALE_OIDC_ISSUER, TALE_OIDC_CLIENT_ID, TALE_OIDC_CLIENT_SECRET et TALE_OIDC_ORG_SLUG. L’issuer correspond à l’origine Tale suivie de /api/auth. Transfère ces octets par ton canal privé d’identifiants et fais lire le JSON par l’application ; ne charge pas le fichier comme script shell et ne le publie pas comme artefact CI. Stdout contient uniquement des métadonnées non sensibles, chemins, tailles et hashes. Une sortie identique n’est réutilisée qu’après vérification de l’état prêt actuel et de tous les artefacts. Une sortie partielle, périmée ou étrangère bloque sans écrasement.

Configurer la plateforme

Utilise tale config pour gérer les paramètres existants de la plateforme via les API natives. Enregistre cette déclaration dans configuration.json pour définir la couleur d’accent et un délai d’inactivité de 45 minutes :

json
{
  "schemaVersion": 1,
  "resources": [
    {
      "kind": "branding",
      "config": {
        "accentColor": "#336699"
      }
    },
    {
      "kind": "governance",
      "key": "session_idle_timeout",
      "config": {
        "enabled": true,
        "idleTimeoutMinutes": 45
      }
    }
  ]
}

Définis TALE_URL avec l’origine HTTPS de l’instance et TALE_ORG_ID avec l’ID natif de l’organisation. Fournis un cookie de session autorisé via TALE_CONFIG_COOKIE ; garde-le hors des arguments et des fichiers versionnés. Valide localement, enregistre et examine le plan, puis applique-le et compare l’état natif :

bash
tale --json config validate --file configuration.json
tale --json config plan --file configuration.json \
  --url "$TALE_URL" --org "$TALE_ORG_ID" --output configuration-plan.json
tale --json --yes config apply --file configuration.json \
  --url "$TALE_URL" --org "$TALE_ORG_ID" \
  --plan configuration-plan.json --receipt configuration-receipt.json
tale --json config read --file configuration.json \
  --url "$TALE_URL" --org "$TALE_ORG_ID"

Les répertoires de sortie et de reçus doivent déjà exister. Une connexion HTTP sur loopback exige aussi --origin avec l’origine HTTPS publique. read indique matches pour chaque ressource déclarée. Le plan précise la portée, les hashes actuels et souhaités, ainsi que les effets natifs. L’application exige la déclaration et la cible exactes. Une modification native concurrente bloque l’écriture. Les ressources non déclarées restent en place. La CLI ne propose ni suppression ni écriture de fichier arbitraire.

Ces types de ressources utilisent les schémas partagés et les permissions natives de la plateforme :

TypeConfigurationPortée
brandingChamps natifs de personnalisationOrganisation
governancePolitique stockée dans un fichier, avec key et config natifOrganisation
providerDéfinition d’un fournisseur et expectedModels facultatifOrganisation
provider-credentialMétadonnées d’identifiants nommés issus de l’environnementOrganisation
knowledge-embeddingFournisseur, modèle, dimensions, endpoint et limites du serveurOrganisation
deploymentParamètres de l’instance, dont le runtime du sandboxInstance

Utilise agent-tools pour gérer uniquement les autorisations d’outils d’un agent existant. Son objet config exige les valeurs exactes de projectId et agentId, ainsi que le tableau complet des tools souhaités, par exemple ["task_find", "task_get", "task_review"]. Inclus chaque autorisation à conserver ; [] retire toutes les autorisations d’outils. Le catalogue natif refuse les noms inconnus et normalise l’ordre et les doublons avant de calculer le hash.

Pour appliquer cette ressource, tu dois pouvoir modifier le projet actif, et l’agent ne doit pas être géré par la plateforme. Les membres peuvent lire cette configuration limitée. Tous les autres champs restent inchangés, y compris les instructions, le modèle et les autorisations exactes d’accès aux secrets. Le hash natif refuse les modifications concurrentes des outils ; une sélection modifiée invalide aussi les enregistrements complets d’agent fondés sur un état périmé. Une sélection équivalente ne change ni horodatage ni entrée d’audit. Si le runtime ne prend pas en charge la capacité demandée, il refuse l’opération. Relis les outils après l’application et conserve le reçu en attente pour reprendre une application interrompue.

Utilise agent-model pour choisir la configuration d’exécution des prochains démarrages d’un agent existant. Son objet config exige les valeurs exactes de projectId et agentId, ainsi que harness, model et un modelProvider explicitement choisi dans le catalogue natif. La plateforme vérifie cette combinaison et les identifiants disponibles ; elle ne choisit jamais un autre fournisseur. Les mêmes droits de modification du projet et la même restriction concernant les agents gérés par la plateforme s’appliquent. Les instructions, outils, compétences, connecteurs et autorisations d’accès aux secrets restent inchangés. Le travail déjà en attente ou en cours conserve la configuration complète enregistrée lors de son admission. Une sélection identique ne change rien ; une sélection modifiée invalide les enregistrements complets d’agent fondés sur un état périmé. Un fournisseur qui n’était pas défini apparaît comme null à la relecture, mais une déclaration doit en choisir un. Utilise les commandes existantes de planification, d’application et de lecture, et conserve le reçu si l’application est interrompue.

Utilise task-review-context pour inscrire une tâche opérationnelle vierge pour un seul réviseur. Son config contient projectId, taskId, reviewerAgentId et enabled. Par défaut, la tâche doit déjà exister, sans historique d’exécution, de révision ou de travail de mise en œuvre. Pour la créer, ajoute createIfMissing: true à côté de kind et de config, et choisis un UUID stable pour taskId. Avec les droits de modification du projet, tu peux alors créer la tâche dans le backlog et l’inscrire dans une seule transaction. Si l’inscription échoue, aucune tâche ni modification des compteurs ou du journal d’audit ne subsiste. Le réviseur doit déjà disposer de task_review ; l’inscription n’accorde aucun outil et ne lance aucun travail. Les tâches existantes restent soumises aux contrôles de tâche vierge ; une identité occupée n’est jamais écrasée. Après une interruption, conserve le même ID et le reçu en attente. La désactivation conserve le réviseur et la finalité du contexte.

Les politiques de conservation et DSAR exigent leurs workflows natifs dédiés. Interromps les envois, la synchronisation et les crawls avant de changer de modèle d’embedding. La CLI vérifie le nombre de documents et de sites web dans toute l’organisation ; elle ne verrouille pas l’import et ne migre pas les vecteurs existants. Pour une organisation avec des documents ou des sites web enregistrés, un changement de modèle exige une migration native distincte de l’index. Une modification limitée à minSimilarity, maxConcurrentRequests, minTokensPerSecond, maxTokensPerMinute ou maxRequestsPerMinute laisse les vecteurs existants valables et échappe donc à cette vérification. Les paramètres d’instance exigent aussi la liste native des éditeurs autorisés. L’application autonome signale restartRequired pour les paramètres de démarrage ; les enregistrer ne les active pas encore. Examine les effets du plan avant de l’appliquer.

Les déploiements gérés utilisent le même moteur via configuration. Ajoute cet exemple à la déclaration de déploiement quand un opérateur externe sert déjà le fournisseur. Remplace l’endpoint et le catalogue synthétiques par des valeurs vérifiées, puis injecte EXTERNAL_PROVIDER_SECRET depuis ton gestionnaire de secrets :

json
{
  "environment": {
    "TALE_PROVIDER_KEY_EXTERNAL": {
      "env": "EXTERNAL_PROVIDER_SECRET"
    }
  },
  "configuration": {
    "schemaVersion": 1,
    "resources": [
      {
        "kind": "provider",
        "config": {
          "name": "external-chat",
          "displayName": "External chat",
          "apiFormat": "openai",
          "baseUrl": "https://models.example.invalid/v1",
          "catalog": {
            "source": "models-endpoint"
          },
          "embedding": "unknown",
          "auth": [
            {
              "method": "env"
            }
          ]
        },
        "expectedModels": [
          {
            "id": "Example-chat",
            "provider": "external-chat",
            "tags": ["chat"],
            "supportsTools": true,
            "supportsVision": false,
            "contextWindow": 131072
          }
        ]
      },
      {
        "kind": "provider-credential",
        "config": {
          "providerSlug": "external-chat",
          "authMethod": "env",
          "name": "Managed external provider",
          "envName": "TALE_PROVIDER_KEY_EXTERNAL",
          "modelAllowlist": ["Example-chat"]
        }
      }
    ]
  }
}

envName suit le préfixe natif TALE_PROVIDER_KEY_ et la limite de 40 caractères. Chaque alias exige une référence environment obligatoire. Les endpoints privés exigent aussi une référence explicite TALE_ALLOW_PRIVATE_PROVIDER_HOSTS dont la valeur est 1 ; les restrictions natives d’hôtes restent actives. expectedModels vérifie le catalogue fraîchement résolu par Tale lors de la relecture. Ce contrôle ne prouve ni la capacité d’inférence, ni la latence, ni les résultats métier.

Pour la sélection du modèle de vision, utilise governance avec key: "vision_model" et les champs natifs providerSlug/modelId. L’embedding utilise knowledge-embedding avec providerSlug, model, dimensions et baseUrl, plus les réglages facultatifs que la plateforme garde à côté du modèle dans embedding.json : minSimilarity, le plancher de cosinus de l’assistant pour ce modèle, et les limites du serveur maxConcurrentRequests, minTokensPerSecond, maxTokensPerMinute et maxRequestsPerMinute (Doser les requêtes vers un serveur d’embedding auto-hébergé). Chacun suit la règle de la plateforme elle-même : une valeur le fixe, une clé omise laisse ce que le fichier contient (une valeur posée à la main survit à une release qui ne la mentionne pas), et null l’efface — "minSimilarity": null, par exemple, est la seule façon de retirer un plancher par la CLI. Pour remplacer les identifiants par défaut, déclare aussi les anciens identifiants d’environnement avec isDefault: false ; la CLI applique ce changement explicite en premier. Les secrets ne figurent ni dans la déclaration ni dans le reçu.

La configuration native suit la vérification d’identité et précède les versions de configuration. Le reçu native.configuration lie les hashes de déclaration et de bundle, l’organisation, les hashes des ressources et les révisions natives. Un reçu en attente précède la première écriture. Si une ressource échoue ensuite, les changements précédents peuvent rester en place. Relis l’état natif et le reçu avant de reprendre le même plan vérifié. Le compare-and-set natif protège chaque ressource des modifications concurrentes d’un admin ; aucune transaction ne couvre l’ensemble. Conserve l’état du déploiement, les snapshots et les reçus pour la restauration.

Les déploiements gérés activent aussi une ressource deployment déclarée avant de signaler qu’ils sont prêts. La CLI conserve l’activation en attente, attend jusqu’à cinq minutes la fin des sessions du spawner sandbox vérifié, puis redémarre ce conteneur. Si des sessions restent actives, l’opération reste en attente. Le reçu configurationActivation enregistre la configuration montée et le démarrage observé du conteneur ; de nouveaux contrôles de santé doivent réussir. Une nouvelle tentative vérifie un redémarrage déjà accepté. Après une activation réussie, une nouvelle exécution sans changement ne redémarre pas le service.

Remplacer un plan de configuration en attente

Si un plan interrompu peut encore aboutir, relance ce même plan. Le remplacement explicite sert lorsque les réglages déclarés ne peuvent plus fonctionner, par exemple si le point de terminaison d’embedding n’est plus disponible. Conserve le reçu existant : il garde la trace des modifications qui ont pu atteindre la plateforme.

  1. Lis le reçu en attente et compare les ressources déclarées à leur état actuel sur la plateforme. Enregistre les réglages corrigés dans replacement-configuration.json, avec la même cible et exactement les mêmes identifiants de ressources. Le remplacement ne permet ni d’ajouter ni de retirer des ressources.
  2. Calcule le hash du champ plan du reçu conservé, pas celui du reçu entier ni du plan de remplacement. La commande suivante nécessite Bun et utilise du JSON canonique : clés d’objets triées récursivement, ordre des tableaux conservé et aucun espace.
bash
PENDING_PLAN_SHA=$(bun -e '
  const receipt = await Bun.file(process.argv[1]).json();
  if (receipt.phase !== "pending") throw new Error("Receipt is not pending");
  function canonical(value) {
    if (Array.isArray(value)) return "[" + value.map(canonical).join(",") + "]";
    if (value !== null && typeof value === "object") {
      return "{" + Object.keys(value).sort().map(key =>
        JSON.stringify(key) + ":" + canonical(value[key])
      ).join(",") + "}";
    }
    return JSON.stringify(value);
  }
  console.log(new Bun.CryptoHasher("sha256")
    .update(canonical(receipt.plan)).digest("hex"));
' configuration-receipt.json)
  1. Crée un nouveau plan à partir de la déclaration corrigée et examine-le avant de l’appliquer :
bash
tale --json config plan --file replacement-configuration.json \
  --url "$TALE_URL" --org "$TALE_ORG_ID" --output replacement-plan.json

Une fois le plan vérifié, applique-le avec le chemin du reçu d’origine et le hash du plan conservé :

bash
tale --json --yes config apply --file replacement-configuration.json \
  --url "$TALE_URL" --org "$TALE_ORG_ID" \
  --plan replacement-plan.json --receipt configuration-receipt.json \
  --supersedes-pending-plan "$PENDING_PLAN_SHA"
tale --json config read --file replacement-configuration.json \
  --url "$TALE_URL" --org "$TALE_ORG_ID"

Chaque ressource doit encore correspondre à l’état initial, à la modification prévue ou au résultat vérifié du plan en attente. Toute modification indépendante sur la plateforme bloque le remplacement avant la première écriture. Clarifie cet écart avec l’administrateur concerné ; ne supprime pas le reçu pour contourner la vérification.

Le reçu conserve le plan précédent et ses ressources vérifiées sous superseded, y compris après une interruption ou une nouvelle tentative. Vérifie qu’il atteint phase: "ready" et que config read indique des ressources conformes. Omet ce paramètre de sélection ponctuel lors des opérations suivantes.

Pour un déploiement géré, définis supersedesPendingConfigurationPlan dans la spécification de déploiement avec ce même hash du plan conservé, puis corrige configuration. Prépare et examine ensuite un nouveau bundle. Si celui-ci remplace aussi un déploiement en attente, sélectionne séparément le hash de ce dernier avec supersedesPendingBundle. Ce paramètre de bundle ne suffit pas à autoriser le remplacement du plan de configuration natif. Retire les deux paramètres de reprise des spécifications suivantes une fois l’opération prête.

Pour chaque ressource, la preuve publique native.configuration donne le hash prévu dans configurationSha256 et celui de l’état relu sur la plateforme dans observedConfigurationSha256. Ils peuvent différer lorsqu’un réglage conserve une valeur existante, par exemple lorsqu’un seuil de similarité ou une limite du serveur d’embedding est omis. Le reçu privé conserve l’état exact observé pour permettre la reprise.

Exploitation

tale status — afficher l'état actuel du déploiement. Aucun argument.

tale deploy smoke --url <url> — vérifie un déploiement en service par son URL publique, comme un navigateur y accède. Sans --full, la commande n'envoie aucun identifiant et n'écrit rien : tu peux donc la lancer contre n'importe quel déploiement, y compris la production. Elle vérifie /api/health (et la version, avec --expected-version <version>), la disponibilité de l'API, le shell de l'application et son script, une lecture de session anonyme, et que /events et /api/app refusent un visiteur sans session. Le http:// non chiffré n'est accepté que pour localhost ; avec ta propre autorité de certification, définis NODE_EXTRA_CA_CERTS sur son certificat racine.

  • --full — se connecte en plus avec un compte dédié et parcourt un scénario utilisateur : ouvrir le flux de mises à jour en direct de l'organisation, créer une tâche, attendre sa mise à jour en direct, la relire puis la supprimer (un compte qui ne peut pas supprimer de tâches l'archive à la place). Renseigne le compte dans TALE_SMOKE_EMAIL et TALE_SMOKE_PASSWORD ; il ne doit pas exiger de second facteur. Si le compte ne voit aucun projet, la première exécution en crée un nommé « Tale deployment smoke », que les exécutions suivantes réutilisent.
  • --chat — avec --full, lance aussi un tour de chat sur le premier modèle disponible pour le compte. Ce tour consomme des tokens de modèle ; la conversation part ensuite à la corbeille, après l'arrêt du tour s'il est encore en cours.
  • --organization <id-or-slug>, --project <id> — où se déroule le scénario ; par défaut, la première organisation et le premier projet du compte.
  • --timeout <seconds> — limite de chaque requête et de chaque attente (par défaut 15) ; --turn-timeout <seconds> limite le tour de chat (par défaut 120).

Avec --json, le rapport liste chaque vérification avec son statut (pass, fail ou skip), sa durée et sa raison. Le code de sortie 0 signifie que toutes les vérifications ont réussi, 5 qu'au moins une a échoué et 2 qu'une option est invalide. Le scénario complet retire sa tâche (supprimée ou archivée) et se déconnecte même après une vérification en échec.

tale logs <service> — diffuser les logs d'un service (service est l'un des services en cours d'exécution ; sur une stack de dev sans déploiement, la commande retombe sur le conteneur de dev).

  • -f, --follow — suivre la sortie des logs au fil de l'écriture.
  • -n, --tail <lines> — n'afficher que les N dernières lignes.
  • --since <duration> — afficher les logs depuis une durée relative (p. ex. 1h, 30m).
  • -c, --color <color> — cibler une couleur de déploiement précise (blue ou green).
  • --raw — diffuser la sortie brute, non filtrée (aucune classification).

tale backup — sauvegarder les volumes de projet existants pris en charge. Aucun argument. Les bases et buckets externes exigent leurs propres sauvegardes ; consulte Portée des sauvegardes.

tale restore [snapshot-id] — restaurer un snapshot ; sans id, la liste des snapshots disponibles s'affiche.

  • --stop — arrêter les conteneurs du projet avant la restauration.
  • -y, --yes — ignorer l'invite de confirmation.

tale rollback — revenir à la version patch précédente (niveau patch uniquement). Demande confirmation au préalable.

  • -y, --yes — ignorer l'invite de confirmation (requis en mode non-interactif).

Maintenance

tale update — changer la version d’une instance de workspace : mettre à jour la CLI et synchroniser les fichiers projet, puis lancer tale deploy. Les commandes du workspace s’alignent sur cette version. Les bundles gérés et releases de configuration gardent leur révision de CLI fixée séparément.

  • -v, --version <version> — mettre à jour vers exactement cette version (p. ex. 0.9.0) au lieu de la dernière ; autorise les rétrogradations.
  • -f, --force — forcer la re-synchronisation et écraser les fichiers projet modifiés localement.
  • --dry-run — montrer ce qui changerait sans rien modifier.

tale migrate — reprovisionner les valeurs par défaut intégrées pour chaque organisation sur le déploiement en cours — la même étape idempotente que chaque déploiement exécute, à la demande. Les migrations de schéma ne sont pas une commande : le backend les applique au démarrage, donc un conteneur déployé est toujours sur son propre schéma.

  • --dry-run — montrer ce qui serait exécuté sans l'exécuter.

tale cleanup — supprimer les conteneurs inactifs (couleur non courante). Aucun argument.

tale reset — supprimer tous les conteneurs blue-green.

  • -f, --force — ignorer l'invite de confirmation.
  • -a, --all — supprimer aussi les conteneurs d'infrastructure avec état.
  • --dry-run — prévisualiser la réinitialisation sans rien modifier.

tale uninstall — supprimer le binaire CLI tale de ce système. Il demande confirmation avant de supprimer quoi que ce soit et propose aussi de déconnecter l’appareil de sandbox de cette machine, de retirer ~/.tale-daemon laissé par l’ancien tale daemon et de démanteler les ressources Docker et les fichiers d'un projet. Sans --purge, un projet et ses conteneurs restent intacts — lance tale reset --all à l'intérieur pour les supprimer. Si l’appareil de sandbox ne peut pas être arrêté, rien n’est désinstallé.

  • -f, --force — ignorer l'invite de confirmation (supprime uniquement le binaire ; les nettoyages optionnels nécessitent toujours --purge).
  • --purge — déconnecter aussi l’appareil de sandbox et supprimer ses espaces de travail, retirer ~/.tale-daemon et, pour un projet trouvé depuis le répertoire courant, démanteler ses ressources Docker et supprimer ses fichiers. Irréversible.
  • --dry-run — montrer ce qui serait supprimé sans rien supprimer.

tale config show — afficher le répertoire du projet local résolu et la version de CLI. Hors d’un projet, la commande signale qu’aucun projet n’a été trouvé et se termine sans erreur.

Releases de configuration

Ces commandes utilisent la révision de CLI choisie sans alignement sur une instance ni opération Docker. Publier les configurations d’un client couvre les descripteurs, commits source, identifiants et reprises. L’identité par défaut est le SHA source complet : manifeste schéma 4/compilateur 3 avec releaseRef === sourceCommit. Les numéros entiers de version native restent distincts.

build, verify et stage exigent --repo <directory>, --descriptor <path> et --automation <name>. Le chemin du descripteur est relatif au dépôt. Celui du manifeste à vérifier peut être absolu ou relatif au dépôt.

CommandeOptions obligatoiresOptions facultatives
tale config build--source-commit <sha>--skill-owner <user-id> (requis pour les skills propres au paquet), --output <directory>, compatibilité --config-version <version>
tale config verify--manifest <path>--rebuild pour la reconstruction exacte hors ligne
tale config stage--config-ref <sha>, --output <directory>--skill-owner <user-id>, --client <name>, --deployment-ref <sha>

La préparation source exige un checkout dont HEAD est ce commit complet et une sortie hors du checkout. Elle reconstruit les contenus committés sans commit de catalogue généré. stage --config-version choisit explicitement l’ancien parcours compatible et exige --catalogue-commit, --catalogue-repository, --client et --ops-commit. Ne combine pas --config-ref et --config-version.

Les commandes natives exigent --stage <directory>, --url <origin>, --org <id> et --project <id>. HTTPS est obligatoire sauf pour HTTP local ; utilise --origin <origin> pour l’origine canonique du navigateur derrière un proxy. Les deux lisent TALE_CONFIG_COOKIE uniquement dans l’environnement.

CommandeOptions obligatoiresOptions facultatives
tale config deploy--receipt <path>--yes global pour un déploiement sans interaction déjà autorisé
tale config verify-nativeAucune autre option obligatoire--native-version <number>, --allow-retained

Les deux commandes natives acceptent les attentes exactes --config-ref, --source-repository, --artifact-sha256, --deployment-ref, --client et --automation. Les anciens arguments de catalogue restent compatibles. verify-native est en lecture seule ; --allow-retained vérifie une version conservée choisie explicitement sans la présenter comme déployée. Sans --native-version, la vérification choisit la dernière version enregistrée. L’API native expose le contrat de tâche uniquement pour la version déployée ; une vérification conservée ne peut donc pas attester ce champ.

Les commandes de configuration n’ont pas de --dry-run : utilise stage, verify --rebuild et verify-native. Le JSON de succès est {ok:true,command:"config <verb>",data}. Les données de build et de vérification incluent automationName, releaseRef, sourceCommit, artifactSha256, artifactPath et verified ; la sortie compatible emploie configVersion à la place de releaseRef. Les reçus de transfert SHA et les reçus natifs utilisent le schéma 2. Un résultat de déploiement contient automationVersion et unchanged ; le champ explicite verified appartient aux sorties de vérification.

Appareil de sandbox

Ces commandes exécutent les sandboxes de ton organisation Tale sur la machine où tu les lances. Exécuter les sandboxes sur tes propres appareils explique comment ajouter un appareil dans Paramètres > Sandboxes, qui fournit la commande connect. L’appareil conserve sa configuration et ses espaces de travail dans ~/.tale/sandbox ; TALE_SANDBOX_HOME les déplace.

tale sandbox connect <site> --token <token> — connecter cette machine à l’organisation qui a émis le jeton : la commande vérifie Docker (et propose de l’installer), enregistre la machine et démarre les conteneurs de l’appareil dans la version du serveur. site est ton site Tale, par exemple https://your-org.tale.dev. Le jeton (tsdj_…) ne fonctionne qu’une fois, dans l’heure. Linux et macOS uniquement.

  • --name <name> — le nom que Tale affiche pour l’appareil (par défaut : le nom d’hôte de la machine). Les caractères autres que A–Z, a–z, les chiffres, ., - et _ deviennent des tirets.
  • --max-sessions <n> — combien de sandboxes tournent ici en même temps, de 1 à 256 (par défaut : une pour deux CPU et pour 4 Gio de mémoire utilisables par Docker, 16 au plus).
  • --no-auto-update — ne pas suivre automatiquement la version du serveur ; lance plutôt tale sandbox update après chaque mise à jour de Tale.
  • --docker-socket <path> — le socket Docker qu’utilisent les conteneurs de l’appareil, pour Docker rootless (par défaut : /var/run/docker.sock).

tale sandbox status — afficher la connexion, l’organisation, la version et les conteneurs de l’appareil, ainsi que les sandboxes en cours d’exécution. Aucun argument.

tale sandbox update — passer immédiatement l’appareil à la version du serveur et reprendre les adresses actuelles du serveur pour ses sandboxes (nécessaire après un changement d’adresse du backend ou de la passerelle de modèles). Aucun argument.

tale sandbox logs — afficher le journal de l’appareil.

  • -f, --follow — continuer à afficher les nouvelles lignes.
  • --tail <lines> — combien de lignes afficher d’abord (par défaut : 200).

tale sandbox disconnect — retirer l’appareil de son organisation, arrêter ses sandboxes et supprimer leurs espaces de travail de cette machine. La commande demande d’abord confirmation et ne change rien tant que Docker ne tourne pas. Si le serveur est injoignable, la machine est tout de même nettoyée, et un administrateur retire l’appareil dans Paramètres > Sandboxes.

  • --keep-data — conserver les espaces de travail sur cette machine.
  • -f, --force — ignorer l’invite de confirmation.

Avancé

tale auth hash-password — afficher le hachage Better Auth d’un mot de passe, pour un administrateur de secours.

La commande lit le mot de passe sur stdin, ou dans une invite masquée avec confirmation dans un terminal interactif. Elle refuse un mot de passe qui ne respecte pas la politique de mot de passe par défaut de la plateforme et n’affiche que le hachage.

tale auth reset-owner — réinitialiser les identifiants du compte propriétaire.

Pour une récupération manuelle, lance la commande sans options dans un terminal interactif. Le mot de passe se saisit dans une invite masquée, sans figurer dans l’historique du shell ni les arguments. La réinitialisation invalide les sessions existantes.

  • -e, --email <email> — définir une nouvelle adresse e-mail du propriétaire.
  • -p, --password <password> — définir un nouveau mot de passe du propriétaire.

Dépannage

  • tale deploy vise la mauvaise machine. La CLI utilise le contexte Docker / DOCKER_HOST de ton shell. Bascule avec docker context use … (ou définis DOCKER_HOST) pour qu'il pointe sur l'hôte voulu, puis relance.
  • tale deploy utilise le mauvais alias d'hôte. L'hôte sur lequel le proxy répond vient de HOST dans le .env du projet, pas d'un stockage CLI séparé. Modifie .env ou passe --host pour le remplacer le temps d'un lancement.
  • L'installeur échoue sur macOS parce que le binaire ne peut pas s'exécuter. Quand le binaire fraîchement installé refuse de démarrer (p. ex. Gatekeeper le tue), l'installeur échoue avec des pistes de récupération au lieu d'annoncer un succès — suis-les, puis relance l'installeur.
  • tale introuvable après installation sous Linux. L'installeur dépose le binaire dans /usr/local/bin ; vérifie que le répertoire est dans le PATH de l'utilisateur (echo $PATH).

Pour l’exploitation courante, consulte Mises à jour, Sauvegardes et restauration ou Architecture des conteneurs.