hachiflow.com

Cet article parle de Buzz, notre produit précédent. Aujourd'hui, nous construisons Waggle.

Dogfood

L'agent est la couche de rendu

Nous avons donné une boîte mail à notre agent marketing. Un client nous écrit, Gary V lit le message dans un canal de notre propre workspace hébergé chez hachiflow, rédige la réponse et l'envoie quand un fondateur dit go. Du mail vers AgentMail, vers le webhook d'un workflow, vers un agent coéquipier : tout sur du logiciel déjà publié, zéro infrastructure maison. Autant que nous sachions, personne n'avait publié ce câblage exact.

Une URL, un en-tête, une étape YAML

Les pièces étaient déjà en rayon. AgentMail est une boîte mail API-first conçue pour les agents : vous créez une boîte via l'API, elle reçoit le courrier et envoie un webhook vers l'URL de votre choix dès qu'un message arrive. Buzz, le workspace open source publié par Block (hachiflow est indépendant et n'est pas affilié à Block), embarque un moteur de workflows directement sur le relais. Chaque workspace sur hachiflow.chat l'intègre, donc les workflows déclenchés par webhook fonctionnent dès le premier jour, sans serveur à faire tourner vous-même.

Un workflow avec un déclencheur webhook obtient un point d'accès comme POST https://yourteam.hachiflow.chat/hooks/9f4c21e7-6b3d-4a8e-b02f-c75d10a94e63, authentifié par un en-tête X-Webhook-Secret. Pointez le webhook d'AgentMail vers cette URL, mettez le secret dans l'en-tête, et le courrier entrant atterrit dans votre canal.

C'est toute l'intégration : une URL, un en-tête, une étape YAML. La capture d'écran ci-dessous montre tout le côté Buzz, et le terminal qui suit montre tout le contrat, avec des valeurs d'exemple délibérément fausses.

L'éditeur de workflows de Buzz : un workflow nommé customer-marketing-emails sur le canal marketing, avec un déclencheur webhook, une seule étape Send Message dont le texte est la sonnette d'une ligne mentionnant Gary V, et la bascule formulaire/YAML dans le coin.
Toute l'intégration côté Buzz : un déclencheur webhook et 1 étape Send Message. La seule ligne de texte envoyée est la sonnette.
tout le contrat
# simulez la livraison d'AgentMail : même URL, même en-tête $ curl -X POST \ -H 'X-Webhook-Secret: 7d81f3a2-4c96-4b0e-a2d5-e6f4903b17c8' \ -H 'Content-Type: application/json' \ --data '{"event":"message.received"}' \ https://yourteam.hachiflow.chat/hooks/9f4c21e7-6b3d-4a8e-b02f-c75d10a94e63 # la sonnette tombe dans le canal et l'agent va chercher le vrai mail

Les deux valeurs sont des exemples délibérément faux : le vrai UUID du hook et le vrai secret sont générés à la création du workflow, et le secret ne vit que dans la configuration du webhook AgentMail.

Essai 1 : le mur de JSON

Notre premier workflow a fait la chose évidente : il injectait le payload directement dans le canal avec {{trigger.message}}. Résultat : un mur de JSON brut. En-têtes, résultats SPF, métadonnées des pièces jointes, toute l'enveloppe en un seul paragraphe. Il est conservé dans la capture d'écran plus bas, juste au-dessus de ce qui l'a remplacé.

La limite est précise, et nous avons lu le Rust pour la confirmer. Aujourd'hui, les templates de workflow de Buzz n'extraient que les clés de premier niveau du corps du webhook. Un objet imbriqué s'affiche comme un seul bloc converti en chaîne : il n'existe pas de {{trigger.message.from}}, et les seuls filtres de template sont truncate et npub. Afficher proprement un payload de webhook imbriqué dans un message de workflow n'est pas possible pour l'instant.

Ce n'est pas un reproche. Le moteur est jeune et la surface des templates va grandir. Mais aujourd'hui, le conseil honnête est le suivant : ne prévoyez pas de mettre en forme votre payload de webhook dans le workflow, prévoyez de faire sans.

Ne faites pas le rendu dans le workflow. Ne le faites pas du tout.

La sortie nous crevait les yeux dans tous les autres messages du canal. Les messages d'agents dans Buzz sont très lisibles, parce que le client affiche le contenu des messages en markdown façon GitHub. Le workflow ne pouvait pas mettre en forme le courrier, mais le coéquipier à qui il le livrait met en forme tout ce qu'il dit. Nous avons donc inversé l'architecture et cessé complètement de faire le rendu dans le workflow.

Le message du workflow est désormais une sonnette d'une ligne qui @mentionne l'agent. Gary V détient lui-même les outils AgentMail, via leur serveur MCP hébergé, limité à cette seule boîte. Quand la sonnette retentit, il récupère le courrier non lu, publie dans le canal une carte markdown lisible avec son brouillon de réponse, envoie la réponse en fil sur le message d'origine via l'API AgentMail, et étiquette le message comme traité pour que rien ne soit traité deux fois.

L'agent est la couche de rendu. Le workflow est un réveil. Et l'approbation n'a pas bougé : Gary rédige dans le canal, et un fondateur dit go avant que quoi que ce soit ne sorte de la maison.

mail du client de n'importe où boîte AgentMail API-first · webhooks workflow sur votre relais déclencheur webhook POST /hooks/… · X-Webhook-Secret sonnette d'une ligne #marketing Gary V agent · tient les outils de la boîte la @mention réveille carte markdown + brouillon MCP : récupérer · répondre · étiqueter fondateur : go
La forme qui marche : le workflow ne fait que sonner, l'agent lit, rend et répond. L'approbation reste dans le canal.
Le canal marketing dans Buzz. En haut, un ancien message qui rend le payload du webhook comme un mur de JSON brut ; en dessous, la sonnette d'une ligne qui l'a remplacé ; et dans le panneau de fil à droite, le résumé lisible de l'agent et sa réponse envoyée.
Avant et après dans un seul cadre : en haut le bloc de JSON brut de l'essai 1, en dessous la sonnette d'une ligne qui l'a remplacé, à droite le résumé lisible de Gary et sa réponse en fil.

La mention qui ne réveille personne

Le piège 1 nous a coûté 3 séries de tests. Les mentions dans les messages de workflow sont résolues côté serveur : le relais compare le @Name du texte de votre étape aux membres du canal, par nom d'affichage. Si 2 membres partagent un nom d'affichage, le relais ne réveille délibérément personne. Pas d'erreur, pas de correspondance partielle, aucun log visible. Le silence.

Nous avions un doublon périmé : un ancien « Gary V », mort, était encore membre du canal à côté du vrai, si bien que chaque sonnette retentissait pour personne. Comme règle contre les erreurs d'aiguillage, c'est raisonnable : vous ne voulez pas qu'un workflow devine lequel de 2 membres homonymes réveiller. Comme expérience de débogage, c'est brutal, parce que rien nulle part ne vous dit que c'est arrivé. Nous avons exclu le membre périmé et la sonnette a retenti.

L'auteur affiché est cosmétique

Le piège 2 est plus subtil. Un message de workflow a l'air de venir de vous. Ce n'est pas le cas. Le client affiche l'attribution ; cryptographiquement, le message est signé par la propre clé du relais.

Le filtre de réponse de Gary était réglé sur « propriétaire uniquement », et ce filtre vérifie la signature, pas l'auteur affiché. Il a donc vu arriver la sonnette, constaté qu'elle n'était pas signée par son propriétaire, et l'a ignorée, à juste titre. Le filtre a raison, l'auteur affiché est cosmétique, et le correctif consiste à ajouter la clé du relais à la liste autorisée de l'agent, pour que les messages de workflow signés par le relais comptent comme un réveil.

Nous l'avons découvert en lisant le code source de buzz-acp, et l'amont s'est débattu avec le même problème : un correctif a été fusionné puis annulé. Donc si votre agent est tagué et ne se réveille jamais, alors qu'il n'y en a exactement qu'1 dans le canal, voici pourquoi.

Un dernier pour la route

Un petit, venu de l'éditeur YAML des workflows. Une valeur texte qui commence par @ doit être entre guillemets, parce qu'un @ nu ne peut pas commencer un scalaire YAML. Et collez avec soin : nous avons un jour réussi à ajouter un second document YAML entier dans le champ de texte du message, et l'éditeur l'a accepté sans broncher. Les vues formulaire et YAML sont 2 portes vers la même étape ; celle du formulaire mord moins.

Réparer les outils qu'on a en main

Chaque série de tests était un vrai mail envoyé depuis notre propre domaine avec higgs, notre CLI pour Proton Mail qui pilote Proton Mail Bridge en IMAP et SMTP. Aucun mock : chaque test a traversé le vrai internet, atterri dans la vraie boîte et fait retentir la vraie sonnette, et c'est exactement comme ça que nous avons attrapé des pièges qu'une fixture n'aurait jamais fait apparaître.

Le dogfooding a joué dans les deux sens. En plein débogage, nous avons découvert que higgs send ne savait pas parler à Bridge d'emblée, alors nous l'avons corrigé et avons publié higgs v1.3.0 le soir même. Voilà à quoi ressemble le vrai travail de câblage entre agents : la moitié du temps, vous réparez les outils que vous avez en main.

Qualité alpha, et c'est livré

Tout ce qui précède tourne aujourd'hui sur n'importe quel workspace hachiflow : 50 $ par mois, forfaitaire, personnes et agents illimités, vos propres clés LLM, un serveur dédié. Rien ici n'a demandé d'infrastructure sur mesure. AgentMail est un produit auquel vous pouvez vous inscrire, le moteur de workflows est livré dans chaque workspace, et l'agent est un membre de votre équipe comme un autre.

Buzz est jeune et ceci est un câblage de qualité alpha, avec des aspérités, et c'est exactement pour cela que nous publions les pièges plutôt qu'un best-of. Si vous voulez une boîte mail avec un coéquipier derrière, commencez sur hachiflow.com.

← Toutes les notes