Aller au contenu
ColliePWA

13/Documentation

Sécurité : à lire avant toute exécution

Ce qu'un Collie expose, les mécanismes de défense, et l'association d'un appareil, l'identifiant pour chaque requête

Collie fournit par conception un accès shell distant à votre machine. Un seul appel à l'API Collie envoie des frappes arbitraires directement à un panneau de terminal actif. Tout appareil que vous avez associé peut lire chaque panneau (code source, secrets, variables d'environnement, sortie de l'agent) et exécuter des commandes en tant que votre utilisateur. Depuis la version 1.18.0, chaque requête API nécessite le jeton d'un appareil associé, lectures comprises ; la porte d'entrée est donc l'association elle-même : quiconque peut joindre l'URL et détient un code d'association valide obtient le même accès. Avant la 1.18.0, quiconque pouvait joindre l'URL pouvait lire chaque panneau.

Il n'y a aucun bac à sable ni aucune liste d'autorisation de commandes, car filtrer les commandes irait à l'encontre du but de l'outil. Considérez chaque appareil associé comme un accès root, et chaque code d'association comme un mot de passe. Révoquez immédiatement un appareil perdu avec collie devices revoke <label>. L'association réduit le risque mais ne l'élimine pas ; maintenez donc l'URL sur un réseau privé comme un tailnet, jamais sur l'internet public.

Associer un appareil : l'identifiant d'accès en écriture

Depuis la version 1.18.0, cet identifiant est exigé pour chaque requête, y compris en lecture, et non plus pour les seules écritures.

# on the host — prints an 8-character code and a QR code, good for 10 minutes
bin/collie pair

L'association est toujours active, et les lectures exigent le jeton d'association au même titre que les écritures. Tant qu'un appareil n'est pas associé, Collie renvoie 403 device not paired à chaque téléphone et navigateur. Exécutez d'abord collie pair sur l'hôte avant d'ouvrir Collie sur le téléphone.

Ouvrez Collie sur le téléphone, allez dans Paramètres → Appareils associés, puis saisissez le code avec un libellé pour l'appareil, ou scannez le code QR affiché par la commande pour ouvrir directement cet écran avec le code prérempli. Le téléphone enregistre le jeton retourné. Collie ne conserve que le hash, et le jeton n'est affiché qu'une seule fois. Vous n'avez pas besoin de redémarrer le processus ; le démon en cours d'exécution applique les associations et les révocations à la requête suivante.

Les deux systèmes de filtrage d'appareils répondent à des questions différentes, et vous pouvez utiliser l'un, l'autre, les deux ou aucun des deux :

demandefait confiance àrévoquer en
COLLIE_DEVICE_HEADERcet appareil figure-t-il sur la liste de l'opérateur ?votre proxy, pour injecter un nom qu'il a nettoyémodifiant COLLIE_DEVICE_ALLOWLIST, puis en redémarrant
associationcet appareil possède-t-il un identifiant que j'ai émis ?rien sur le réseaucollie devices revoke <label> : en direct

L'association ne nécessite aucune infrastructure supplémentaire. Elle s'adapte à une configuration directe avec tailscale serve où aucun proxy n'existe pour injecter des en-têtes.

L'appairage filtre chaque route /api, lectures incluses. Seules deux routes restent ouvertes : /api/health, interrogée par un moniteur ou un répartiteur de charge, et /api/pair, requise par un appareil avant d'obtenir un jeton. /api/health renvoie le build, le mode crew et trois compteurs des sept derniers jours (la fréquence à laquelle la zone de saisie est apparue libre, la fréquence à laquelle elle n'a pas pu être lue, et la fréquence à laquelle une personne a envoyé manuellement après un écran que Collie n'a pas pu lire). Les compteurs ne nomment aucun panneau, aucun texte et aucune personne.

L'en-tête de l'appareil filtre les écritures et deux lectures : le Vue Fichiers, qui peut afficher chaque fichier du dossier d'un espace de travail, et le Parcourir de la page New, qui liste les noms de dossiers sous home (ADR 0086).

bin/collie devices list             # what holds a credential, and when each was last seen
bin/collie devices revoke old-phone # effective immediately, no restart

Une nouvelle installation n'a aucun appareil associé, donc Collie ne répond à aucun téléphone tant que vous n'exécutez pas collie pair. Révoquer le dernier appareil ne rouvre pas Collie : chaque appareil reçoit alors device not paired. Pour corriger la situation, exécutez collie pair sur l'hôte et associez à nouveau le téléphone. collie doctor affiche un avertissement tant qu'aucun appareil n'est associé.

Remarque. Le lien de crew et la standby door conservent leurs propres identifiants. Un lead transmet une lecture à un membre via TLS mutuel épinglé et le secret de crew, de sorte qu'un membre n'a pas besoin de son propre appareil associé (crew).

Cinq tentatives de code erronées invalident le code, ce qui nécessite d'exécuter collie pair à nouveau. De plus, le bridge refuse plus de dix tentatives d'association par adresse source et par minute avec 429 et Retry-After: 60. Derrière une front door sur la même machine, l'adresse source correspond à la dernière entrée X-Forwarded-For, celle ajoutée par la front door. Pour tout autre pair, cet en-tête est ignoré. Les compteurs résident en mémoire et sont réinitialisés au redémarrage du bridge.

Lectures propres au CLI

À chaque démarrage, le bridge écrit un nouveau secret aléatoire dans local-secret au sein de son dossier d'état. collie doctor et collie crew update l'envoient pour lire leur propre bridge sur la même machine. Le fichier est restreint au propriétaire, de sorte que seul votre compte peut le lire, et un arrêt propre le supprime. Le bridge ne l'accepte que pour les lectures, jamais pour une écriture ni pour la vue Files, et jamais depuis une autre machine. Il n'accepte le secret que depuis le loopback, et jamais sur une requête portant un en-tête de proxy tel que X-Forwarded-For. Un membre du crew qui lie COLLIE_HOST à son adresse tailnet n'a rien sur le loopback ; dans ce cas, le bridge l'accepte aussi depuis les propres adresses de cette machine. Un simple relais TCP sur la même machine, tel que socat ou ssh -L, peut toujours transmettre le secret. Ce fichier garantit que le secret reste le vôtre, conservez donc le dossier d'état restreint au propriétaire.

Définir une expiration pour un appareil

Un appareil associé conserve son jeton jusqu'à ce que vous le révoquiez. Pour limiter cela, transmettez une durée de validité lors de l'association :

bin/collie pair --expires 30d             # also 12h, 2w; at most 3650d
bin/collie devices set-expiry pixel 90d   # a new lifetime, counted from now
bin/collie devices clear-expiry pixel     # no expiry again

La durée de validité est décomptée à partir du moment où le téléphone valide le code. Sans --expires, un jeton n'expire jamais, exactement comme avant, et aucun jeton existant n'est modifié. Après l'expiration, le bridge refuse le jeton avec device expired au lieu de device not paired. Le téléphone alors efface ce que l'association a laissé et affiche Associer à nouveau dans Settings ; exécutez donc collie pair pour obtenir un nouveau code. collie devices list et l'écran Settings indiquent l'expiration de chaque appareil. Un appareil expiré reste dans la liste jusqu'à ce que vous le révoquiez ou lui attribuiez une nouvelle expiration avec set-expiry. Pour l'associer à nouveau, vous pouvez utiliser le même nom : la nouvelle association remplace l'entrée expirée et révoque son ancien jeton, et le journal d'audit enregistre la révocation. Un nom qu'un appareil utilise encore, avec un jeton non expiré, est refusé. La standby door d'un deputy de crew refuse également un jeton expiré.

Sur un hôte exécutant plusieurs instances, préfixez les commandes avec COLLIE_INSTANCE=<name> et ouvrez l'URL de cette instance spécifique sur le téléphone (Plusieurs instances de Collie sur un même hôte).

Ce que la dissociation efface sur le téléphone

Lorsqu'une association prend fin, le téléphone supprime ce que Collie y a stocké. Cela se produit lorsque vous dissociez le téléphone depuis Settings, et lorsque le bridge refuse son jeton avec device not paired ou device expired.

Le téléphone supprime le jeton, chaque brouillon non envoyé, le texte du panneau et le herd enregistrés, l'abonnement push, les confirmations « Sans confirmation » et les caches de Collie à l'exception de l'app shell. Vos paramètres restent : le thème, la langue, les épingles et autres préférences ne contiennent aucun texte de session. Les paramètres vous demandent de confirmer avant de révoquer un appareil.

L'effacement propre au téléphone est le seul effectué. Le bridge n'envoie aucun en-tête Clear-Site-Data, car cet en-tête effacerait également vos paramètres et l'application hors ligne, et sur un nom d'hôte partagé, il toucherait aussi les autres applications hébergées là.

Si le bridge ne peut pas lire sa liste d'appareils associés, par exemple en cas de fichier partiellement écrit, il répond 503 pairing unavailable à la place. Le téléphone conserve alors son jeton et tout ce qu'il a stocké, puis réessaie.

Ce que le téléphone conserve

Le téléphone conserve une copie restreinte et limitée de ce qu'il a vu en dernier, afin qu'une ouverture à froid puisse l'afficher lorsque le bridge est inaccessible. Chaque élément ci-dessous a une limite de taille et une durée de vie.

ÉlémentEmplacementDuréeÀ la dissociation
Jeton d'associationlocalStoragejusqu'à la dissociation, la révocation ou l'expirationsupprimé
Paramètres : thème, langue, épingleslocalStoragejusqu'à modificationconservé
Brouillons non envoyéslocalStorage48 heuressupprimé
Point de terminaison pushlocalStoragejusqu'à modificationsupprimé
Enveloppe de l'applicationCache Storagejusqu'au prochain buildconservé
Polices et titres des notifications pushCache Storagejusqu'au remplacementsupprimé
Fichiers du moteur et du modèle vocal Whistle (uniquement si vous avez choisi de les copier)Cache Storagejusqu'à ce que vous les supprimiezsupprimé
Texte de Herd et du volet, tel que vu la dernière foisIndexedDB collie-store24 heuressupprimé
Derniers tours de Chat de chaque voletIndexedDB collie-store1 jour, ou le paramètre « Conserver le chat sur ce téléphone »supprimé

Les deux dernières lignes correspondent au stockage sur l'appareil. Il ne contient que du texte déjà masqué par le bridge, au maximum 256 Kio par volet et 10 Mio au total, et supprime les entrées les plus anciennes en premier. Le texte du volet et les tours de Chat reçoivent chacun la moitié des 256 Kio d'un volet, de sorte que l'un n'éjecte jamais l'autre. Les tours de Chat sont conservés entiers, tels que Chat les a affichés, jamais sous la forme de l'écran brut du terminal. « Conserver le chat sur ce téléphone » réglé sur Off n'en conserve aucun et supprime ceux déjà stockés. Lorsqu'un volet demande un mot de passe, le téléphone supprime les entrées de ce volet. Aucun élément du stockage ne peut envoyer de touche ou de réponse. Les suppressions lors de la dissociation sont celles indiquées dans Ce que la dissociation efface sur le téléphone.

Le sélecteur d'applications du téléphone peut également afficher un volet. Lorsque vous quittez Collie, le téléphone conserve une capture de l'écran pour sa liste d'applications récentes, et cette image peut montrer le texte du volet. Une application web ne peut pas empêcher cela : Android a pris sa capture avant que la page ne soit informée de son passage en arrière-plan (testé sur un Pixel, le 08/10/2026), et iOS n'offre aucune garantie non plus. Si cela vous importe, verrouillez le téléphone ou fermez Collie avant de le confier à quelqu'un.

Modèle de risque

Limites de sécurité principales et risques :

  • Il s'exécute avec vos autorisations utilisateur. Collie hérite de l'ensemble de vos droits d'accès, notamment ~/.ssh, git push --force, rm -rf et sudo.
  • L'authentification identifie les appareils, pas les personnes physiques. Tailscale vérifie le terminal matériel plutôt que l'utilisateur qui le tient. Il n'y a pas de mot de passe ni de session utilisateur ; un téléphone déverrouillé ou volé fournit un shell ouvert. L'association lie l'accès à un identifiant sur l'appareil (ci-dessus), révoquez donc immédiatement un téléphone perdu. Le verrouillage d'inactivité intégré efface simplement un écran sans surveillance et ne constitue aucune véritable limite de sécurité (ADR 0007).
  • Tous les utilisateurs locaux du système peuvent atteindre le port. Les sockets standard des multiplexeurs de terminaux (tmux, zellij, herdr) utilisent les permissions du système de fichiers pour restreindre l'accès aux autres utilisateurs locaux. Collie écoute sur un port TCP local, ce qui l'expose à chaque UID local. Les lectures nécessitent le jeton d'association ; un autre utilisateur local ne possédant aucun jeton ne lit donc rien d'autre que /api/health. Le jeton constitue la limite : un utilisateur local capable de lire le profil de votre navigateur peut également lire le jeton (ARCHITECTURE.md §6).
  • Une permission retenue attend l'appui d'une personne. Avec collie hooks install claude --hold-permissions, le hook de permission de Claude interroge le pont via un fichier socket. Seul votre utilisateur peut l'ouvrir (mode 0600 dans un dossier 0700). Le hook vérifie le propriétaire du socket, le dossier et le répertoire d'état parent avant de se connecter. Le pont ne répond que pour un processus qu'il place sur un panneau. Il ne répond jamais seul. Un appui doit transmettre le hachage de ce que la carte affichait. Une carte d'écran ne répond jamais à une requête dont le dialogue n'apparaît pas à l'écran (Autorisations retenues pour le téléphone).
  • La vue Files lit les fichiers directement sur votre disque. Elle affiche tout fichier situé dans le dossier d'un espace de travail, à l'exception d'un dossier .git, des dossiers d'état et de configuration propres à Collie, et des fichiers dont le nom correspond à un secret d'état de Collie. Elle exige donc un appareil autorisé, comme pour une écriture (ADR 0083).
  • L'option Browse de la page New liste les noms de dossiers sous votre répertoire personnel. Noms uniquement, avec les limites de la vue Files : aucun dossier commençant par un point sauf saisie manuelle, pas de .git, aucun dossier d'état ou de configuration Collie, aucun lien hors de home, au maximum 200 lignes. Requiert également un appareil autorisé (Dossiers favoris et récents).
  • Tout appareil associé peut lire les fichiers situés dans le dossier de l'espace de travail. Cela inclut les fichiers .env. N'associez que les appareils auxquels vous confiez l'accès au shell lui-même.
  • Les fichiers d'identifiants situés sous le dossier d'un espace de travail sont lisibles. Un espace de travail ouvert dans ~/.claude, ~/.codex, ~/.config/gh ou ~/.ssh affiche ce qui s'y trouve. Il en va de même pour le .env d'un second Collie dont le dossier de configuration se trouve sous l'espace de travail. Un lien physique à l'intérieur du dossier pointant vers un fichier extérieur n'est pas intercepté non plus.
  • Un appareil associé peut ajouter des lanceurs. Avec la valeur par défaut [phone] adds = true, un téléphone peut ajouter une ligne construite à partir d'une recette : un agent accompagné de puces d'options dont les drapeaux sont choisis par le bridge dans sa propre table. Une ligne saisie à la main nécessite free_text = true, qui est désactivé par défaut. Une recette peut toujours ignorer les demandes d'autorisation. Une telle ligne porte un badge « Sans confirmation », et chaque appareil la confirme une fois. Révoquer un appareil supprime les lignes qu'il a ajoutées. Définissez adds = false pour désactiver toutes les lignes ajoutées par un téléphone (Vos propres lanceurs, ADR 0094).
  • Un appareil associé peut exécuter une commande ponctuelle. Avec la valeur par défaut [phone] run = true, un téléphone peut saisir une ligne qu'il a rédigée dans un nouveau shell sur une machine. Cela n'ajoute aucun privilège, car un téléphone associé peut déjà ouvrir un shell et y taper du texte. La ligne suit la règle des caractères pour ligne libre, et le bridge la refuse en l'absence d'appareil associé. Chaque commande démarrée est conservée, jusqu'à 12, dans commands-recent.json dans le dossier d'état (mode 0600). Une ligne qui semble contenir un secret (une affectation telle que TOKEN=…, une URL avec mot de passe ou un mot comme token ou password) s'exécute mais n'est pas conservée. Cette vérification étant une estimation, un secret peut tout de même se glisser dans la liste ; le journal d'audit n'enregistre que le premier mot d'une ligne et sa longueur. Dissocier ou révoquer un appareil laisse la liste telle quelle, car réexécuter une ligne nécessite un appareil associé. Définissez run = false pour retirer le raccourci (Commandes ponctuelles, ADR 0095).
  • Chaque machine conserve les lignes shell que vous envoyez via Collie. Sent conserve les lignes envoyées à un panneau shell, ainsi que chaque commande ponctuelle, dans sent.jsonl au sein du dossier d'état (mode 0600). Un appareil associé peut le lire, tout comme il peut lire les panneaux. Certains secrets restent protégés (Sent : les lignes shell envoyées).
  • Une instance unique expose toutes les sessions Herdr. Par défaut, un seul processus Collie prend en charge chaque session Herdr découverte sous la racine de configuration de Herdr, y compris les sessions sandbox (Multi-session).
  • Les écritures sont enregistrées dans <state-dir>/audit.log, qui correspond à ~/.local/state/collie/audit.log sauf si COLLIE_STATE_DIR le déplace. Le serveur consigne l'ensemble des frappes entrantes, des réponses, des téléversements de fichiers et des événements de cycle de vie des panneaux/onglets. Notez qu'un journal d'audit offre une visibilité a posteriori plutôt qu'un contrôle d'accès. Les caractères envoyés en mode Type ne sont jamais écrits dans le journal : COLLIE_AUDIT_CONTENT=none masque chacun d'eux, et l'aperçu par défaut enregistre uniquement un décompte de marques •. Les touches nommées comme Entrée et Ctrl+C restent lisibles (ARCHITECTURE.md §6). Les réponses, envois, arrêts, appuis sur les boutons, démarrages, réouvertures et renommages d'un agent durable sont également enregistrés (Ce qui est journalisé).
  • En-têtes de réponse. Chaque réponse transmet X-Content-Type-Options: nosniff, Referrer-Policy: no-referrer et Permissions-Policy: camera=(), geolocation=(), microphone=(self), payment=(), usb=(). Le microphone reste autorisé pour le réglage de dictée vocale mains libres. La directive Content-Security-Policy sur l'enveloppe de l'application inclut object-src 'none', form-action 'self' et frame-ancestors 'none'. Strict-Transport-Security est envoyé uniquement lorsqu'une requête arrive via HTTPS, soit sur un écouteur TLS, soit avec X-Forwarded-Proto: https provenant de votre proxy. Il couvre le nom d'hôte ayant répondu et non ses sous-domaines, car Collie partage souvent un domaine parent avec d'autres services. Le bridge lui-même communique en HTTP brut derrière tailscale serve, et un navigateur y ignore l'en-tête. Les images servies depuis /api/blobs/ constituent du contenu de session ; elles portent donc Cache-Control: private, no-store et aucun cache ne les conserve, pas même celui du téléphone.
  • Contrôles défensifs par défaut. Collie se lie strictement aux interfaces de bouclage, achemine le trafic uniquement via tailscale serve ou un reverse proxy équivalent, et applique des règles CSP strictes, des vérifications de même origine et la validation de l'en-tête host. Le contenu du panneau est rendu sous forme de nœuds texte React et non via innerHTML. N'utilisez jamais tailscale funnel et n'exposez jamais de port brut. Pour autoriser un matériel spécifique, utilisez directement association ou, si votre proxy injecte des identifiants d'appareils, les deux variables COLLIE_DEVICE_* ci-dessous.
variabledescription
COLLIE_ALLOW_NON_LOOPBACK_BIND=1Désactive la liaison exclusive à l'interface de bouclage ; si non définie, le pont refuse de se lier à 0.0.0.0.
COLLIE_ALLOW_ANY_HOST=1Désactive la validation de l'en-tête host, activée par défaut et bloquante en cas d'erreur.
COLLIE_TRUSTED_USERRejette toute requête dont l'en-tête Tailscale-User-Login est manquant ou ne correspond pas.
COLLIE_TRUSTED_USER_OPTIONAL=1Autorise l'absence d'en-tête Tailscale-User-Login (les nœuds avec des tags n'en envoient jamais).
COLLIE_ACCESS_TEAM + COLLIE_ACCESS_AUDCloudflare Tunnel uniquement. Rejette toute requête distante sauf si son Cf-Access-Jwt-Assertion est validé pour cette application Access. Seuls un processus local sur le loopback, /api/health et les liens crew l'ignorent, et l'appairage s'applique toujours. Les autres points d'entrée, tels que tailscale serve, sont également refusés (Cloudflare Tunnel).
COLLIE_DEVICE_HEADERNom de l'en-tête que votre proxy injecte avec un identifiant d'appareil.
COLLIE_DEVICE_ALLOWLISTIdentifiants d'appareils autorisés en écriture, séparés par des virgules ; tous les autres appareils restent en lecture seule (docs/deployment.md).
COLLIE_REDACT=offDésactive le masque de secrets sur le texte du volet, les diffs et le texte des fichiers (ci-dessous). Activé par défaut.
COLLIE_SENT=offNe conserve aucun enregistrement des lignes shell envoyées (ci-dessous). Activé par défaut.
🚫 N'utilisez jamais tailscale funnel avec Collie. Funnel route le trafic vers l'Internet public, alors que tailscale serve restreint l'accès à votre tailnet privé. Il n'existe aucun cas d'usage pris en charge pour exécuter Collie sur Funnel.

Restreignez davantage l'accès avec les ACL Tailscale et COLLIE_TRUSTED_USER. Fourni en l'état, sans garantie.

Agents durables

Un agent durable que vous associez est du code que vous exécutez ou déployez, et Collie traite son texte comme non fiable. Un socket privé bloque les autres utilisateurs mais pas un processus de votre propre utilisateur, et un jeton reste le seul filtre sur https. Les règles de confiance par transport, le traitement appliqué par Collie au texte d'un agent durable et les données conservées par le journal d'audit figurent dans Sécurité d'un agent durable.

Le moteur vocal (Whistle)

Whistle exécute du code tiers : un moteur WebAssembly de Cactus Compute. Il tourne sur le téléphone, ou sur l'hôte sous l'utilisateur du bridge. Collie limite ce à quoi ce code peut accéder. Il ne peut pas supprimer totalement cet accès.

  • Intégré en vendoring et figé. Le moteur est composé de deux fichiers, needle.js et needle.wasm, conservés à l'octet près tels que publiés en amont, avec la licence d'origine et une note de provenance (web/public/stt/needle-3-93e88ede/). Un test fige le sha256 des deux fichiers et la liste des seize fonctions que le wasm peut demander à son hôte. Tout nouvel import impose un arrêt. Seul un humain met à jour cette empreinte, après avoir lu le diff. Le modèle possède son propre hash figé, et Collie ne conserve une copie téléchargée que s'il correspond.
  • Sur le téléphone, un worker avec sa propre politique. Le wasm s'exécute dans un worker dédié. Le bridge sert chaque script sous stt/ avec cette politique, et aucune autre page ne la reçoit :
    Content-Security-Policy: default-src 'none'; script-src 'self' 'wasm-unsafe-eval'; base-uri 'none'

    Le worker n'a pas d'accès réseau, pas de DOM et aucun moyen de charger du code distant. Il ne peut pas lire le jeton d'association, situé dans localStorage, et les workers ne possèdent pas de localStorage. Avant toute chose, il compile un minuscule module wasm. Un navigateur qui n'accorde pas au worker sa propre politique refuse cette opération, et Ce téléphone y apparaît comme indisponible.

  • La politique de la page ne change pas. La politique du document ne reçoit jamais 'wasm-unsafe-eval', et conserve connect-src 'self'.
  • Ce à quoi le worker peut encore accéder. Il peut lire et écrire dans l'IndexedDB et le Cache Storage de cette origine, qu'aucune directive de politique ne verrouille. collie-store contient le texte récent du panneau et du Chat (Ce que le téléphone conserve). Ce texte était déjà masqué, mais il reste lisible. Cet accès est accepté et documenté dans l'ADR. Si cela devient un problème, l'étape suivante consistera à isoler le worker dans une frame sandboxée.
  • Sur l'hôte, un enfant du propre binaire de Collie. Un processus enfant éphémère par dictée exécute _whistle-transcribe avec une liste fixe d'arguments générée par Collie. Il vérifie le moteur, le wasm et le modèle par rapport à leurs empreintes avant de compiler quoi que ce soit. Il a un délai limite de 60 secondes, interrompu par SIGKILL, une sortie plafonnée à 256 Kio et au maximum deux exécutions simultanées. Il ne reçoit aucune variable COLLIE_* du bridge. Le bridge n'en définit que deux, le dossier d'état et le dossier d'installation, avec des chemins qu'il a lui-même résolus. Rien de la requête n'atteint la liste des arguments, à l'exception de l'enregistrement.
  • Un second appel sortant, déclenché par l'action d'une personne. La vérification des mises à jour est le premier. Le téléchargement du modèle est le second : un seul fichier, depuis une adresse Hugging Face figée, écrit uniquement après validation de son hash. Un téléphone n'appelle jamais Hugging Face. Il copie le modèle depuis l'hôte, avec le jeton d'association. Les routes nécessitent un appareil avec accès en écriture, ne tournent que sur le lead, n'autorisent qu'un téléchargement à la fois et sont auditées.
  • La configuration depuis Settings est une exception à la règle « la configuration est un acte CLI ». Les fournisseurs qui stockent un identifiant ou désignent une commande restent dans le terminal. Whistle ne fait rien de tout cela. Un jeton d'écriture dérobé permet déjà de taper dans les terminaux et de lancer une mise à jour ; l'action de configuration ne lui accorde donc aucun droit supplémentaire.
  • Le passage à Codex depuis Settings est l'autre exception. Un appareil avec accès en écriture peut basculer l'hôte entre Whistle, Codex et Off, et rien d'autre. Codex requiert un consentement complet, les mêmes termes que ceux affichés par collie stt setup, et une validation sur J'accepte ; le bridge exécute ensuite le test propre au CLI. Un jeton d'écriture dérobé pourrait rediriger la synthèse vocale de l'hôte vers le compte ChatGPT connecté de l'opérateur. Il ne peut pas ajouter de clé ou de commande, ni en remplacer une. Le jeton peut déjà taper codex dans un terminal. L'ADR 0097 analyse ce risque. Une modification depuis Settings écrit également le nom de l'appareil associé, tel que renseigné lors de l'association, ainsi que la date et l'heure dans stt.json, afin que Synthèse vocale de l'hôte puisse indiquer qui l'a modifié en dernier. Aucun jeton ni aucune adresse n'est enregistré. Une exécution de collie stt setup supprime cette ligne.
  • Les appareils associés peuvent lire ce que désignent les paramètres vocaux de l'hôte, uniquement par leur nom. Il s'agit du nom de la commande, du nom d'un fichier de modèle et du nom d'hôte d'un service vocal, jamais d'un chemin, d'un argument, d'une clé ou d'un chemin d'URL.

Pourquoi cette conception : ADR 0096. Les étapes d'installation se trouvent dans Saisie vocale et Web Push.

Walky-talky

Walky talky achemine les messages entre les sessions d'agents ; cette section précise donc ce qu'un message prouve et ce qu'il ne prouve pas. Les commandes se trouvent dans Walky-talky.

# in .env, then run `collie restart`
COLLIE_WALKY=off

Cette ligne indique à cette machine de refuser tout message destiné à ses panneaux. Le CLI sur la machine peut toujours en envoyer.

  • Une clé d'équipe signe un message d'une machine à l'autre. Un membre signe un message avec sa clé d'équipe. Le lead vérifie la signature avec la clé qu'il a épinglée pour ce membre, puis ajoute sa propre signature pour la machine destinataire. Une installation individuelle ne possède pas de clé d'équipe. Elle ne signe rien et n'envoie rien hors de la machine.
  • Le récepteur vérifie l'expéditeur, sur la parole du lead. Un membre n'épingle que son lead. Le lead envoie donc le certificat de l'expéditeur avec le message, et signe une courte déclaration attestant que ce certificat appartient bien à ce membre de l'équipe. La machine réceptrice vérifie cette déclaration, puis vérifie la signature de l'expéditeur par rapport au certificat. En cas d'échec de vérification, elle refuse le message. Elle fait toujours confiance au lead quant à la composition de l'équipe.
  • Seul le lead peut renvoyer un résultat. Le lead transmet à un membre les résultats de ses propres messages. Le membre ne les accepte que de son lead épinglé, et uniquement pour un message qu'il a envoyé et qu'il journalise encore. Les résultats et l'enregistrement de ce que le lead a reçu restent en mémoire et disparaissent après 10 minutes.
  • La carte sur le téléphone nécessite le journal. Le téléphone n'affiche une carte de message que lorsque le journal du pont contient l'identifiant de ce message. Un en-tête qu'un agent affiche uniquement à l'écran reste en texte brut, avec la mention « aucun enregistrement dans le journal sur cette machine ».
  • Un jeton de panneau n'est pas un secret. Le jeton dans une adresse, telle que #k3f9, empêche un message d'atteindre une nouvelle session ayant repris l'identifiant d'un panneau fermé. collie walky who l'affiche à chaque agent, et <stateDir>/walky/instances.json est lisible par votre utilisateur. Il ne prouve en rien l'identité de l'expéditeur.
  • Chaque machine traversée par un message le conserve. La machine de l'expéditeur, le lead et la machine réceptrice consignent chacun le message dans <stateDir>/walky/. Le journal conserve 7 jours et au maximum 2 000 lignes. N'insérez jamais de secret dans un message.
  • Le message d'un agent correspond aux propos d'un pair. Le panneau reçoit une ligne avec l'en-tête de l'expéditeur et aucun corps. L'agent lit le corps comme la sortie de collie walky inbox <id>, qu'un harnais traite comme une donnée et non comme votre instruction. La compétence installée indique à l'agent d'évaluer le contenu et de ne jamais exécuter de commande destructive à la demande d'un pair.
Remarque. Un agent s'exécute sous votre utilisateur, il peut donc lire la clé d'équipage et ouvrir le socket local. Il pourrait signer un message ou s'approprier un volet qui n'est pas le sien. La signature protège un message lors de son transfert entre machines et indique au destinataire quelle machine l'a envoyé. Elle ne vous protège pas contre un programme menteur qui tourne sur la même machine.

Walky talky n'ajoute aucun appel sortant. Un message vers une autre machine emprunte le lien d'équipage déjà existant, et aucun modèle, service cloud ou tiers ne le voit.

Ce qui quitte la machine est masqué

Collie masque les formes de secrets reconnues dans le texte des volets et le contenu des fichiers avant qu'ils n'atteignent un téléphone.

# in your .env, only to turn the mask off; it is on by default
COLLIE_REDACT=off

Le masque s'exécute sur le bridge, sur cinq chemins : le miroir de terminal, les vues Chat et History, chaque notification push, les diffs dans la vue Changes et le texte des fichiers dans la vue Files. Les éléments masqués sont remplacés par des marques • de même largeur, préservant ainsi les colonnes et le nombre de lignes. Un préfixe de fournisseur reste lisible, de sorte que sk-o•••• indique toujours ce qui a été masqué.

Il ne correspond qu'aux formats à haute confiance :

formatexemple de ce qui est masqué
clés d'API à préfixesk-…, sk-ant-…, sk-or-v1-…, ghp_…, github_pat_…, xoxb-…, AKIA…, AIza…, glpat-…, npm_…
JWTtrois parties en base64url, la première commençant par eyJ
clés privées PEMchaque ligne entre BEGIN … PRIVATE KEY et sa ligne END
jetons porteurle jeton après Bearer , 20 caractères ou plus
valeurs nomméesla valeur après password=, secret:, token=, api_key: et similaires, 8 caractères ou plus
Attention. Il s'agit d'une atténuation, pas d'une garantie. Un mot de passe brut isolé, une valeur brute en hexadécimal ou base64, et une clé avec un préfixe absent de la liste sont ignorés volontairement. Un motif pour les couvrir masquerait du texte et du code ordinaires sur chaque écran.

Du texte ordinaire est parfois masqué aussi, par exemple une ligne de texte ou de YAML contenant token: something. Ce que vous saisissez et envoyez n'est jamais masqué, et la piste d'audit applique ses propres règles (COLLIE_AUDIT_CONTENT).

L'interrupteur se trouve uniquement sur le bridge, via COLLIE_REDACT. Paramètres → Système l'affiche en lecture seule, sous l'intitulé "Secret masking". Le téléphone n'a pas d'interrupteur à dessein : un interrupteur sur le téléphone permettrait à tout téléphone appairé, ou volé, de désactiver le masque. Pour lire une valeur masquée, lisez-la sur la machine. La première fois qu'un panneau affiche du texte masqué, une brève ligne sur le téléphone vous l'indique, une fois par appareil. Si vous collez du texte masqué dans une réponse, un avertissement sous la zone de saisie indique que le panneau reçoit les points, pas le secret.

Dans une crew, chaque membre masque son propre texte, et le lead le masque à nouveau avant que votre téléphone ne le reçoive. Le lead masque le miroir, le Chat, l'historique, les diffs, le texte des fichiers et les titres de panneau d'un membre avec le même masque qu'il utilise pour lui-même ; ainsi, un membre qui tourne encore en 1.17.x ne peut pas envoyer une clé en clair à votre téléphone. Le texte déjà masqué reste tel quel lorsqu'il est masqué à nouveau. Le texte n'arrive démasqué sur le téléphone que si COLLIE_REDACT=off est activé à la fois sur le lead et sur le membre. Un cas particulier : un membre en 1.17.x ne masque rien lui-même, donc si un secret figure dans les lignes avec lesquelles une réponse est vérifiée, le téléphone peut refuser cette réponse avec "The screen changed before that could be sent". La réponse attend alors que le membre tourne en 1.18.0.

Si le lead ne peut pas lire la réponse d'un membre pour la masquer, il ne la transmet pas. Le téléphone affiche alors cette lecture en échec, comme pour un membre qu'il ne peut pas joindre.

Une notification push ne nomme également un panneau que par le nom que vous lui avez donné : le label du panneau, le nom /rename de Claude ou le nom d'un onglet à panneau unique. Elle n'utilise jamais le titre défini par un programme dans le panneau, car n'importe quel programme peut définir ce titre, et un titre peut contenir un chemin, une commande ou un secret. Un panneau sans nom de ce type est appelé par son harness, par exemple claude.

Sent : les lignes shell envoyées

Chaque machine conserve un historique des lignes de shell envoyées via Collie, afin que vous puissiez les retrouver et les réexécuter.

# in your .env, to keep no record on this machine
COLLIE_SENT=off
questionréponse
Ce qui est conservéUne ligne envoyée à un volet de shell, ainsi que chaque commande ponctuelle depuis la page New. Pour chaque ligne : le texte, son dossier, l'heure et la catégorie correspondante.
Ce qui n'est jamais conservéLes prompts destinés à un agent, le texte pour un programme, les clés du panneau Keys, et le mode Type.
Emplacementsent.jsonl dans le dossier d'état, ~/.local/state/collie/ sauf si COLLIE_STATE_DIR le déplace. Le fichier est en mode 0600, dans un dossier à 0700.
DuréeAu maximum 5000 lignes sur chaque machine, et aucune de plus de 365 jours.
Qui peut le lireUn appareil jumelé, car il peut lire les volets vers lesquels les lignes ont été envoyées.
Dans une crewChaque machine conserve son propre fichier. Le lead interroge ses membres lorsque votre téléphone le demande, et ne garde aucune copie.

Collie envoie chaque ligne saisie, puis décide s'il doit la conserver. Il ne conserve rien d'une ligne qui :

  • commence par un espace ou une tabulation,
  • définit une variable, comme TOKEN=abc deploy ou export AWS_SECRET_ACCESS_KEY=…,
  • contient une URL avec un mot de passe, comme https://user:pass@host,
  • contient un mot tel que password, secret, token, bearer ou authorization,
  • correspond à un format reconnu par le masque de secrets, comme une clé ghp_… ou sk-…,
  • dépasse 4096 caractères.

Une telle ligne ne laisse aucune entrée, aucun compteur et aucune ligne de journal contenant son texte.

Pour exclure une ligne, commencez-la par un espace. Le shell l'exécute normalement, et Collie ne conserve rien.

Attention. Cette vérification est une heuristique. Elle conserve un mot de passe passé en simple argument, comme mysql -pPASS, ainsi que tout secret dont le format n'est pas reconnu. Commencez une telle ligne par un espace.

Pour oublier une ligne, utilisez Forget sur sa ligne dans la feuille Sent. Pour oublier toute une machine, utilisez Clear Sent. Les deux fonctionnent tant que COLLIE_SENT=off est défini. Le journal d'audit consigne chaque suppression avec un compteur, jamais la ligne elle-même. Chaque ligne passe par le masque de secrets avant de quitter la machine.

Pourquoi cette conception : ADR 0107.

Fichiers secrets sous Windows

Sur Windows (expérimental), Collie garde ses fichiers secrets réservés à votre compte, SYSTEM et Administrators. « Votre compte » est le compte Windows qui exécute Collie.

NTFS ne possède pas de mode 0600, Collie utilise donc la liste de contrôle d'accès (ACL) de son dossier d'état et de son dossier de configuration. Chaque fichier que Collie y écrit reçoit la même liste. Les dossiers par défaut de votre profil utilisateur sont déjà fermés aux autres utilisateurs standard. La vérification importe surtout lorsque vous déplacez un dossier avec COLLIE_STATE_DIR ou un autre paramètre.

Au démarrage, le bridge vérifie les deux dossiers et leurs fichiers secrets. Si d'autres comptes peuvent en lire un, le bridge le répare, mais seulement dans les dossiers propres à Collie. Il sauvegarde d'abord l'ancienne liste, dans acl-backups dans le dossier d'état, et affiche la commande icacls /restore pour la rétablir. Exécutez cette commande dans un terminal lancé en tant qu'administrateur. Un dossier contenant également d'autres fichiers est vérifié, pas modifié : Collie affiche la commande icacls à exécuter par vos soins. D'autres commandes, comme collie version, se contentent de vérifier et d'avertir.

collie doctor affiche le résultat sous la forme secrets-private. Un dossier accessible en lecture par d'autres comptes est une erreur, accompagnée du correctif. Un dossier que Collie ne peut pas vérifier est un avertissement : cannot confirm.

CasCe qui se passe
Vous copiez, restaurez ou synchronisez le dossier (zip, robocopy sans /SEC, OneDrive, Historique des fichiers, une clé USB)La copie peut perdre la liste. Collie vérifie à nouveau au prochain démarrage.
L'antivirus ou le Dispositif d'accès contrôlé aux dossiers bloque la modificationCollie indique qu'il n'a pas pu rendre le dossier privé, et donne le correctif.
Le dossier est sur FAT, exFAT ou un partage réseauIl n'existe aucune liste que Collie puisse utiliser. Collie affiche cannot confirm. Déplacez le dossier d'état vers un lecteur NTFS sur ce PC.
COLLIE_NO_ACL_REPAIR=1Collie ne modifie aucune liste. Il vérifie et avertit toujours, et doctor continue de faire son rapport.
Remarque. Ceci ne constitue pas une protection contre un administrateur. Les administrateurs peuvent toujours lire les fichiers. Cela ne couvre pas non plus les autres programmes exécutés sous votre compte, les liens physiques dans le dossier, les sauvegardes d'agents dans ~/.claude, ou un dossier d'état situé dans OneDrive ou Documents.

Ce qui quitte votre machine

Rien, par défaut et par principe. Collie n'envoie aucun événement d'installation, aucune statistique d'utilisation, aucun rapport de plantage et aucune télémétrie. Aucun flag ne permet de les activer.

Le seul appel sortant non sollicité est la vérification des mises à jour : une requête HTTPS GET anonyme vers l'API publique des tags de GitHub (bridge/update.ts) qui compare votre version au tag le plus récent. Elle ne transmet aucune donnée sur vous ou votre machine, seulement le user-agent statique collie-update-check.

Le téléchargement du modèle Whistle constitue l'autre appel sortant. Il n'a lieu que lorsqu'une personne appuie sur Télécharger sur l'hôte ou exécute collie stt whistle, et il n'envoie aucune donnée vous concernant (Le moteur vocal (Whistle)).

Walky talky n'ajoute aucun appel sortant. Un message vers une autre machine emprunte le lien d'équipage et ne va nulle part ailleurs (Walky-talky).

Signaler un problème n'ajoute aucun appel sortant. Après des échecs d'envoi, le téléphone peut ouvrir le formulaire de nouveau ticket de GitHub, prérempli, sous forme de lien dans votre propre navigateur. Vous lisez d'abord l'intégralité du texte et le soumettez vous-même sous votre propre compte. Collie ne détient aucun jeton GitHub et le téléphone n'appelle jamais GitHub (ADR 0123).

Si vous définissez COLLIE_ACCESS_TEAM, Collie récupère également les clés publiques de cette équipe Cloudflare Access, au démarrage et une fois par heure. Cet appel reste à votre initiative, et il n'envoie rien non plus sur vous.

Si vous associez un agent durable par URL, Collie appelle cette URL à chaque interrogation avec le jeton porteur de l'agent durable dans l'en-tête Authorization. Cet appel doit également être activé par vos soins, et rien n'est envoyé tant que vous n'en associez pas un (Sécurité d'un agent durable).

Si une collecte venait à être ajoutée, un opt-in explicite serait le maximum : désactivé par défaut, demandé via une question visible, jamais activé par un flag ou par défaut. Revenir sur cet engagement constituerait un changement cassant (ADR 0034).

Modifier cette page sur GitHub

The rest of the documentation