Ce que j’aurais aimé que quelqu’un me dise au sujet du protocole AT et de Bluesky

Traduction de What I Wish Someone Had Told Me About AT Protocol and Bluesky par Rob Ricci le 25 août 2026


Ça fait environ un an que je m’intéresse à atproto (le protocole sur lequel fonctionnent Bluesky, Blacksky et de nombreuses autres applications — dont pckt, où ce blogue est hébergé! —). Je ne suis en aucun cas un expert, mais j’ai lu beaucoup de documentation et de discussions, examiné diverses versions des schémas architecturaux et passé beaucoup de temps à réfléchir aux implications en matière d’évolutivité, de décentralisation et d’autres aspects de la conception et de l’exploitation. Je gère mon propre PDS. J’ai écrit quelques clients qui récupèrent les flux de données provenant des relais et analysent ces données. Je pensais avoir une assez bonne maîtrise du sujet.

Et puis, un dimanche matin, certains services de Bluesky ont connu une panne pendant quelques heures. On en apprend beaucoup plus sur un système à partir de ses défaillances qu’à partir de son fonctionnement normal, et j’ai appris que bon nombre des choses que je croyais savoir n’étaient pas – pas tout à fait fausses, mais tout de même incomplètes pour comprendre comment cet écosystème fonctionne réellement dans la pratique.

Je me suis senti un peu bête d’avoir mis autant de temps à apprendre certaines de ces choses, ou du moins à vraiment en saisir la portée. Ce ne sont pas des secrets, ni rien de ce genre. Il ne s’agit pas non plus de laver le linge sale de l’écosystème en public. Beaucoup de gens savaient déjà tout ça. Mais moi, je ne le savais pas, et peut-être que vous non plus, et c’est pour ça que je les note ici.

Quand on s’initie au Web, on apprend souvent le HTML, le CSS, le HTTP(s), et cela suffit pour créer et héberger des applications Web. Mais ensuite, quelque chose ne fonctionne pas, et… on découvre le DNS. Parce que c’est toujours le DNS. Non pas parce que le DNS est mauvais (bon, peut-être un peu, à certains égards), mais parce qu’il est au cœur du système et qu’il constitue l’un des endroits où se cache une grande partie de la complexité d’Internet. Quand ça fonctionne, c’est génial. Quand ça ne fonctionne pas – ou que ça fonctionne comme prévu, mais pas comme vous le pensiez –, eh bien, c’est le moment de vous familiariser avec le DNS. Désolé.

Ceci ne sera pas un aperçu d’atproto, et n’a pas non plus pour but d’en offrir une vue d’ensemble exhaustive. Je vais écrire en supposant que vous (pensez) connaître l’architecture à un niveau comparable, disons, à celui de l’article de Dan Abramov intitulé « There Are No Instances In atproto »1Voir ma traduction GB, qui est une excellente lecture.

Je tiens à préciser, encore une fois, que je ne suis pas un expert en la matière. J’ai observé des comportements, lu du code, examiné des spécifications, mais il y a d’autres personnes qui connaissent ce sujet bien mieux que moi. Je suis ouvert aux corrections, aux nuances supplémentaires, etc., et je mettrai ce billet à jour. Je tiens également à préciser que je décris le fonctionnement actuel, au mieux de mes capacités. D’après ce que j’ai compris en discutant avec certains membres de l’équipe atproto, ce n’est pas nécessairement ainsi que le système est conçu pour fonctionner, et certains éléments ici sortent, en quelque sorte, du cadre d’atproto lui-même pour être spécifiques à Bluesky. Mais on dispose du système qu’on construit, et non de celui qu’on conçoit.

Voyons donc ce qui a été mis en place.

Le PDS ne se trouve pas tout à fait là où je le pensais

Dans le schéma architectural standard, on voit un référentiel (repo) dans un PDS, les données circulent (peut-être via un relais) vers un AppView qui agrège les données provenant de plusieurs référentiels, et l’application elle-même communique avec l’AppView pour obtenir cette… euh, vue.

Cette dernière étape omet quelque chose.

Dans bien des cas (mais pas toujours!), l’application communique en fait avec le PDS, et non (directement) avec l’AppView.

Le PDS agit comme intermédiaire pour le trafic de l’application vers l’AppView. Lorsqu’une application souhaite effectuer un appel d’API vers l’AppView, elle communique avec le PDS de l’utilisateur, qui, la plupart du temps (attendez, j’y reviendrai dans une minute), transmet cet appel à l’AppView et renvoie la réponse.

Il y a de bonnes raisons de procéder ainsi. L’une des principales est l’authentification : l’utilisateur, par l’intermédiaire de l’application, s’authentifie auprès du PDS, qui détient les clés permettant d’authentifier l’utilisateur auprès du reste du réseau. Ainsi : une requête arrive de l’application, le PDS sait qu’elle provient bien de l’utilisateur puisqu’elle s’inscrit dans une session authentifiée. Le PDS génère un jeton capable de prouver à l’AppView que la demande provient bien de l’utilisateur, et l’envoie avec la demande. Le client n’a ainsi pas à se soucier de toute une série de détails complexes liés aux clés, aux portées, aux audiences, etc. Génial! Vous avez une application complexe qui doit communiquer, de manière authentifiée, avec toute une série de services différents? C’est le problème du PDS. S’assurer que les jetons nécessaires pour communiquer avec chaque service restent valides avant leur expiration? C’est le problème du PDS.

Mais il y a une chose à laquelle le schéma architectural standard ne vous prépare peut-être pas : si votre PDS est hors service ou ne fonctionne pas correctement, l’une des conséquences possibles est que vous ne pourrez plus communiquer avec l’AppView, même si vous êtes déjà connecté.

Rien n’empêche l’application de communiquer directement avec l’AppView, et, en fait, c’est souvent ce qu’elle fait pour les appels ne nécessitant pas d’authentification. Vous pouvez également demander au PDS de vous fournir les jetons nécessaires, afin de les transmettre vous-même à l’AppView. Mais certaines applications, du moins l’application Bluesky (également appelée « social-app »), sont conçues pour utiliser le proxy.

Le PDS dépend de l’AppView de Bluesky – en quelque sorte

J’ai parlé de « l’ » AppView, et j’espère que cela vous a agacé, car, non, il n’y a pas l’ AppView. Dans le cas particulier d’une application indépendante de type Bluesky (comme Blacksky), plusieurs AppViews sont en cours d’exécution et peuvent être utilisées. D’une manière plus générale, d’autres applications peuvent mettre en œuvre leurs propres AppViews, dont les API sont très différentes de celles de l’AppView de Bluesky, ou peuvent fonctionner sans aucune AppView.

Mais.

Il existe des appels que l’on peut effectuer vers une AppView qui ressemble à celle de Bluesky, par l’intermédiaire du PDS, et qui sont vraiment utiles. Et donc, bien sûr, les applications les utilisent. Probablement même si l’application en question n’est pas Bluesky, même si (en fait, surtout si) l’application ne dispose pas de sa propre AppView.

Un bon exemple en est getProfile : les données circulant dans Atmosphere font référence aux comptes par l’entremise de leur did. Mais vous ne voulez pas voir le did dans l’interface utilisateur; vous voulez voir des éléments comme le pseudonyme de l’utilisateur et probablement obtenir d’autres renseignements, comme son nom d’affichage. Qui peut vous fournir ces renseignements? Eh bien, une solution consiste à demander à une AppView! Elle dispose d’un point de terminaison d’API qui vous le dira!

Comment le PDS sait-il à quelle AppView envoyer cette demande? Eh bien…

Chaque demande comporte un en-tête, défini par l’application, qui indique où elle doit être acheminée. Mais que se passe-t-il si l’application omet cet en-tête? Le PDS de référence, fourni par Bluesky, a une AppView par défaut configurée — c’est celle de Bluesky, bien sûr, mais vous pouvez la reconfigurer pour qu’elle pointe vers une autre. Certaines autres implémentations de PDS semblent présenter ce même comportement par défaut — mais pas toutes.

En effet, le fait que le PDS utilise par défaut une AppView particulière lie en quelque sorte ce PDS à cette AppView, n’est-ce pas? D’une certaine manière, cela surprend beaucoup la plupart des gens qui hébergent leur propre PDS, et va à l’encontre de la vision du monde selon laquelle « il n’y a pas d’instances dans ATProto ».

Supposons que je mette en place mon propre PDS.

Je laisse les paramètres par défaut tels quels. Eh bien, de nombreuses applications — y compris beaucoup qui ne sont pas Bluesky — finiront par envoyer une multitude d’appels d’API à l’AppView de Bluesky si elles n’en ont pas spécifiquement demandé une autre. Si l’AppView de Bluesky est hors service, alors ces applications ne fonctionnent pas chez moi à cause d’un paramètre de mon PDS. Hum.

Mais voyons à quoi ressemble réellement ce scénario de défaillance. L’AppView de Bluesky est hors service, donc l’application principale de Bluesky ne fonctionne pas. Mais je suis un gars cool, j’ai mon propre PDS, et je sais que dans atproto, je peux simplement me connecter à n’importe quelle autre application avec le même compte. Je me rends donc sur l’application Web Blacksky et je m’y connecte. Mais certains des appels qu’elle effectue (détails dans un instant) se rabattent sur l’AppView par défaut de mon PDS! Donc, ça ne fonctionne pas vraiment bien! Je dois reconfigurer mon PDS pour pouvoir utiliser correctement l’application Blacksky! Les utilisateurs du PDS Blacksky s’en sortent plutôt bien, car leur PDS (je suppose) pointe déjà vers l’AppView de Blacksky!

Donc oui, je peux me connecter à d’autres applications avec mon compte unique, mais celles qui fonctionnent réellement dépendent de… l’endroit où mon compte est réellement hébergé et de la façon dont celui-ci est configuré.

Ce n’est pas vraiment le monde « sans instance » que nous pensions avoir, n’est-ce pas?

Bon. Alors, peut-être que cette histoire d’« AppView par défaut » est une mauvaise idée. Je connais au moins une implémentation de PDS qui n’en dispose pas : on indique au PDS où les appels doivent être redirigés, sinon on obtient une erreur.

Mais que faire, en tant qu’application sans AppView propre, si le PDS auquel vous vous connectez n’a pas d’AppView par défaut? Hé, je veux juste obtenir des noms d’affichage! Mais c’est… pas clair. Toujours utiliser celle de Bluesky? Avoir une liste et en chercher une qui fonctionne? Laisser l’utilisateur choisir? S’y faire, vous devez avoir la vôtre? Autre chose? Quelle est censée être la sémantique ici?

Oh, et : j’écris tout ça en parlant de pannes. Mais différentes AppViews peuvent renvoyer des données différentes, et (dans certaines régions du monde où il y en a une par défaut), cela est déterminé par votre PDS, donc… ce que vous voyez réellement dans une application peut dépendre de la façon dont votre PDS est configuré. Probablement pas ce à quoi la plupart des gens s’attendraient.

RAW(r) : Certaines sémantiques de l’application Bluesky sont implémentées dans le PDS

Je croyais autrefois que le PDS n’était qu’un endroit où l’on stockait les données utilisateur et les clés. Comme nous l’avons vu plus haut, ce n’est pas tout. Et ce n’est pas tout, car, en fait, le PDS implémente une partie de l’application Bluesky.

Les appels vers le PDS ne servent pas nécessairement uniquement de proxy vers une AppView ou un autre service. Certaines d’entre elles exécutent localement une logique importante. Cela inclut celles auxquelles vous vous attendez probablement, comme la lecture ou l’écriture dans un dépôt.

Mais il y en a d’autres que j’ai trouvées surprenantes, et bon nombre d’entre elles sont axées sur la lecture après écriture (RAW). Voici pourquoi.

Vous rédigez le meilleur message farfelu au monde et cliquez sur « Envoyer ». Naturellement, vous voulez voir immédiatement le fruit de votre travail. Mais ce n’est pas ainsi que fonctionne atproto. Vous l’enregistrez dans votre dépôt. Il passe par le « firehose », traverse un relais (probablement), atteint une AppView, est indexé, et ensuite seulement les gens le voient lorsqu’ils demandent à l’AppView (et/ou à un générateur de flux) quelque chose qui devrait le renvoyer. C’est sacrément rapide la plupart du temps! Mais ce n’est pas instantané. Et parfois, le système s’engorge et cela peut prendre un certain temps. Je veux voir mon chef-d’œuvre maintenant!

Le PDS de référence est là pour vous aider grâce à ses optimisations RAW. Parfois, pour certains appels, il détectera que l’enregistrement que vous venez d’écrire ne fait pas partie de la valeur de retour de l’API, et il l’y glissera discrètement. L’AppView a-t-elle affiché une erreur 404 pour votre œuvre? Le PDS créera un faux fil de discussion, rien que pour vous, juste pour le moment.

Je suis certain que cela a été fait pour améliorer la réactivité. C’est bien plus agréable quand les choses se produisent immédiatement, et le protocole lui-même ne peut garantir les délais de livraison.

Mais réfléchissons à ce que cela signifie.

Cela signifie que votre expérience de l’application est, une fois de plus, déterminée par votre PDS. Vous utilisez une autre implémentation qui n’utilise pas cette astuce? Elle vous semblera moins réactive, même si elle transmet vos données sur le réseau tout aussi rapidement. Mais pire encore, cela intègre davantage de sémantique d’application dans le PDS. Était-ce censé que cet appel renvoie cet enregistrement? C’est de la sémantique d’application! Le PDS doit savoir quels appels d’API devraient renvoyer cet enregistrement, et comment. Et imaginons que Bluesky modifie son AppView pour ne plus joindre les réponses contenant l’émoji 🖕 à leurs messages parents? Pour vous, on aura l’impression que vous avez réussi à faire un doigt d’honneur à votre adversaire. Je vous ai eu!

J’ai délibérément adopté un ton ludique dans cette section (et UNIQUEMENT dans cette section, bien sûr), mais le fond du problème est que les comportements réels de l’application résident dans le PDS : ce que vous voyez, quand vous le voyez, et même si vous le voyez ou non, dépend de votre PDS. Si Bluesky venait à vouloir modifier quoi que ce soit à ce sujet, ce que vous verriez dépendrait de la mise à jour de votre PDS, voire de la mise en œuvre de ces fonctionnalités par celui-ci. Et si une autre application a besoin de ce genre de fonctionnalités ou pourrait en tirer profit? Elle devra convaincre Bluesky, et tous les autres, de les ajouter à leurs implémentations du PDS.

J’ai vu des bogues que vous n’auriez jamais imaginés…

Avant de conclure, examinons un exemple illustrant comment tout ce flux de données transitant par le PDS, ainsi que tout le traitement qu’il effectue, peut donner lieu à des bogues particulièrement pernicieux.

Dans l’appel getFeed, il y a deux étapes : rechercher le générateur de flux, puis le transmettre (ainsi qu’un jeton qui lui est destiné) à l’AppView. Le PDS de référence de Bluesky présente ce qui semble être un bogue : la première partie de ce processus ignore l’AppView qu’on lui a demandé d’utiliser via l’en-tête de proxy, et se contente de communiquer avec l’AppView par défaut du PDS. Alors, oui, en cas de panne de Bluesky? Lancez l’application Blacksky, super, mais si votre PDS est toujours configuré pour utiliser l’AppView de Bluesky, vous ne pourrez pas charger les flux.

J’espère vraiment que c’est un bogue, j’espère vraiment qu’il sera corrigé et que je pourrai modifier ce paragraphe au passé. Mais c’est fou qu’un bogue du PDS puisse avoir ce genre d’effet.

Oh, et tant qu’on y est, cette recherche de flux en deux étapes avec le jeton supplémentaire, c’est… ouais, une sémantique propre à l’application Bluesky. Mais tous les PDS ont intérêt à l’implémenter, sinon les gens qui tentent d’utiliser Bluesky à partir de ceux-ci risquent de ne pas pouvoir charger les flux. Ou du moins certains d’entre eux.

Et ce n’est pas comme ça que je pensais que ça fonctionnait.

Le PDS, c’est l’amour, le PDS, c’est la vie

Je me suis concentré sur le PDS ici parce que je croyais vraiment, sincèrement, que le PDS « ne faisait que » stocker des données et conserver mes clés privées. Je pensais qu’en exploitant le mien, je m’affranchissais de la dépendance à l’infrastructure de Bluesky. Je pensais que le choix de l’implémentation était surtout une question de goût, et non pas un facteur déterminant pour le fonctionnement des applications. Je croyais comprendre les scénarios de défaillance : que Bluesky pouvait tomber en panne, que je n’avais qu’à passer à une autre application, et que tout irait bien.

La réalité n’est pas aussi simple.

La dernière interruption de service s’est nettement mieux déroulée que les précédentes. Et je crois maintenant comprendre un peu pourquoi. Certaines personnes ont réussi, pour la plupart, à simplement continuer d’avancer. Mais cela dépendait du PDS qu’elles utilisaient, ce qui n’est pas censé fonctionner ainsi. Les choses sont bien plus enchevêtrées qu’elles ne le paraissent sur les schémas d’architecture.

Et la quantité de sémantique d’application intégrée au PDS? Je ne m’attendais pas à ça.

S’il vous plaît, parlez-moi des autres éléments qui m’échappent. Je crois que je veux savoir (même si ce n’est peut-être pas le cas).


Fichier Excel des traductions par Gilles en vrac
Fiches avec les premières phrases (et non seulement les titres)
Les caractères gras dans le texte sont de Gilles.

Notes