Chez Lazard Frères Gestion, nous opérons 65 partenaires MFT actifs en production. Une vingtaine utilisent SFTP avec authentification par clé SSH — le reste utilise FTPS avec certificats, ou des protocoles propriétaires. Notre politique RSSI impose la rotation annuelle obligatoire de toutes les clés SFTP. Sans exception. Sans dérogation possible.
Le processus tel qu'il existait avant : identifier les partenaires concernés dans un tableur, rédiger un email à chacun avec la nouvelle clé publique générée manuellement, attendre leur confirmation (et relancer si silence), mettre à jour manuellement dans Axway B2Bi, noter le statut dans le suivi. Simple sur le papier. En pratique : 4 heures par rotation en moyenne, des confirmations qui traînent, des relances oubliées, et des statuts jamais à jour au bon moment.
Pire : ce process dépend entièrement de la disponibilité d'une personne. Si cette personne est en congé pendant une rotation critique, tout s'arrête. Il n'y a pas de mémoire système. Tout est dans les têtes et dans les emails.
J'ai fait le choix de n8n comme orchestrateur bas niveau pour une raison précise : la capacité à construire des sub-workflows autonomes connectés entre eux, avec une granularité de contrôle que les platforms as-a-service ne permettent pas facilement. Claude AI tourne dans chaque agent comme LLM backbone via @n8n/n8n-nodes-langchain.lmChatAnthropic.
L'architecture se compose de deux workflows principaux et quatre agents spécialisés qui s'appellent en tant que sub-workflows :
Ce qui rend cette architecture solide : aucun agent n'agit seul. L'orchestrateur décide toujours. Les agents ne sont que des bras — ils exécutent des tâches discrètes et remontent leur résultat. C'est une distinction fondamentale avec une architecture "agent loop" classique où l'agent prendrait ses propres décisions.
Le workflow principal a trois points d'entrée distincts qui convergent vers le même orchestrateur :
scheduleTrigger se déclenche chaque matin à 8h. Le nœud Set Trigger Auto construit automatiquement le message d'entrée : "Date : [jour] — Scan automatique quotidien — vérifie toutes les clés SFTP et déclenche les actions nécessaires." L'orchestrateur part en autonomie totale.C'est l'un des détails architecturaux les plus fins du projet. Avant d'engager le gros orchestrateur Claude Sonnet pour chaque message Telegram, un agent léger basé sur Claude Haiku 4.5 catégorise le message en une seule valeur : "simple" ou "complexe".
Si simple → réponse directe sans appels d'outils, latence nulle. Si complexe → passage à l'orchestrateur complet avec tous ses agents. Ce pattern Classifier → Routeur réduit drastiquement les coûts d'inférence et la latence pour les interactions quotidiennes banales ("C'est bon pour Acme Corp ?" → réponse en 1 seconde au lieu de 8).
Pattern à retenir : utiliser un modèle léger comme gate avant un modèle puissant est l'un des optimisations les plus efficaces dans un système multi-agents. Le coût d'un appel Haiku est ~20x inférieur à un appel Sonnet. Pour des dizaines d'interactions quotidiennes, ça compte.
Le HITL (Human In The Loop) est la pièce maîtresse du système du point de vue sécurité. Aucune activation B2Bi ne peut se faire sans validation humaine préalable. Ce n'est pas une option — c'est hardcodé dans le system prompt de l'orchestrateur comme règle absolue.
J'ai choisi une validation double canal simultanée. La logique : maximiser la probabilité d'une réponse rapide, quel que soit le contexte où se trouve le validateur.
MFT-YYYYMMDD-HHMMSS (regex /MFT-\d{8}-\d{6}/i), et lien de validation direct. Le RSSI reçoit l'intégralité du contexte pour une décision éclairée.resume. Le second est ignoré. Pas de double validation possible sur le même token.Règle critique découverte en test : après validation HITL par email (token OUI), l'orchestrateur ne doit pas re-déclencher un HITL Telegram. C'est la seule et unique validation requise. J'ai dû l'écrire explicitement dans le system prompt après avoir eu des boucles de double-validation lors des premiers tests.
Toute la gouvernance repose sur une table Airtable SFTP_Partners. C'est la mémoire persistante du système — chaque agent lit et écrit dans cette table. Aucun état n'existe en dehors d'elle.
| # | Partenaire | Date expiration | Statut | Date email envoyé | Date confirmation | Date activation B2Bi | Nb relances | Notes échange |
|---|---|---|---|---|---|---|---|---|
| 1 | Acme Corp | 15/9/2026 | Nouveau | — | — | — | 0 | — |
| 2 | Beta Solutions | 20/8/2024 | En attente | 2/6/2024 | — | — | 1 | En attente de confirmation partenaire. |
| 3 | Gamma Industries | 10/7/2027 | Activé | 25/2/2026 | — | — | 0 | 2026-02-25 — Email de confirmation reçu |
| 4 | Delta Partners | 1/10/2024 | Actif | 4/6/2024 | 6/6/2024 | 7/6/2024 | 0 | Processus fluide. |
| 9 | Iota Consulting | 18/7/2024 | Escalade | 8/6/2024 | — | — | 3 | Troisième relance. [2026-02-24] Escalade RSSI. |
Les statuts forment un cycle d'états strict : Nouveau → Email envoyé → En attente → Confirmé partenaire → Activé. Un statut ne peut pas régresser (sauf correction manuelle). L'escalade est un état terminal qui requiert intervention humaine pour être résolu.
{name: "Activé"} — pas une string directe. Toutes les comparaisons doivent utiliser .name.C'est le workflow le plus sophistiqué en termes de logique de filtrage. Chaque email reçu doit être catégorisé et routé vers le bon traitement — sans jamais déclencher d'action parasite sur un email interne, un auto-reply, ou un email sans lien avec le système.
Le workflow traite les emails entrants via un pipeline de filtres en cascade avant de les passer à l'orchestrateur :
Ce pipeline de filtrage est essentiel. Sans lui, l'orchestrateur recevrait des emails d'absence de bureau comme des confirmations partenaires, des tokens de validation interne comme des questions techniques. J'ai appris ça à la dure lors des premiers tests.
La détection du token HITL mérite une attention particulière. Le filter utilise deux conditions en OR : le token peut être dans le sujet ou dans le corps de l'email (regex /MFT-\d{8}-\d{6}/i). Certains clients email reformatent le sujet lors du reply — il faut couvrir les deux.
Une fois filtré, chaque email arrivant d'un partenaire connu passe à l'orchestrateur email, qui détermine la nature de la réponse et déclenche l'action appropriée :
La partie que j'aurais voulu lire avant de commencer. Chaque bug ici représente entre 30 minutes et une demi-journée de débogage.
Le champ Single Select d'Airtable retourne {name: "Confirmé", color: "..."} et non la string "Confirmé" directement. Toute comparaison === "Confirmé" échoue silencieusement — aucune erreur, juste des conditions qui ne se déclenchent jamais.
Ce bug a affecté 3 nœuds de condition différents dans le workflow. Tous les champs Single Select Airtable sont concernés.
Les messages Telegram contenant des caractères spéciaux français (é, è, ç, à, ù) provoquaient des erreurs de parsing Telegram API avec des messages d'erreur du type "Can't parse message: byte offset N". Telegram attend du UTF-8 pur mais certains encodages en n8n ajoutent des caractères de contrôle.
Le nœud Merge qui attendait la réponse des deux canaux HITL (email + Telegram) se déclenchait dès qu'un seul canal répondait, sans attendre l'autre. Résultat : le workflow continuait avec des données incomplètes ou traitait deux fois la même validation.
Le Gmail Trigger capturait les emails envoyés par le workflow lui-même — notamment les emails "Re: Rotation clés SFTP" en réponse aux partenaires. L'orchestrateur se retrouvait à analyser ses propres messages comme si c'était des réponses partenaires, créant des boucles infinies.
Après réception d'un email de validation avec token OUI, l'Email Orchestrateur re-déclenchait parfois le HITL Agent "pour confirmer sur Telegram aussi". Ce comportement n'était pas inscrit dans le code mais dans le raisonnement LLM — l'orchestrateur pensait que deux validations valaient mieux qu'une.
Moral de l'histoire : ce qui semble évident pour un humain doit être écrit explicitement pour un LLM qui prend des décisions autonomes.
J'ai ajouté des champs Airtable au fil des besoins pendant le développement. Certaines formules calculées référençaient des noms de champs qui avaient été renommés entre-temps. Les erreurs de formule Airtable ne se propagent pas comme exceptions dans n8n — elles retournent simplement des valeurs nulles.
Les messages vocaux Telegram ne peuvent pas être transcrits directement depuis l'URL fournie par le trigger — l'URL expire très rapidement. Il faut d'abord télécharger le fichier audio avec un nœud Telegram dédié, puis passer le binaire à Whisper pour transcription.
Le system prompt de l'orchestrateur principal contient une section de règles absolues qui ne peuvent jamais être overridées par les inputs utilisateur. C'est la zone de sécurité du système.
J'aurais dû concevoir le schéma Airtable complet avant d'écrire la moindre ligne de workflow. Ajouter des champs au fil de l'eau a causé le Bug #6 et m'a coûté deux jours de refactoring. La règle : modéliser tous les états possibles d'un partenaire avant de coder la moindre transition.
Le Bug #5 m'a appris quelque chose d'important : ce qu'on considère comme évident pour un humain ("une validation suffit") doit être écrit explicitement dans le system prompt. Un LLM raisonnant de manière autonome peut parfaitement décider que deux validations valent mieux qu'une — et ce n'est pas une erreur de raisonnement, c'est une inférence valide depuis son point de vue. La précision du system prompt est tout.
Les premiers déclenchements réels ont révélé 3 bugs simultanément. Un environnement de test dédié avec des partenaires factices (ligne Airtable avec une adresse email de test) est indispensable. Tester les filtres Gmail avec des emails envoyés depuis différents clients pour couvrir les edge cases d'encodage.
Le memoryBufferWindow en n8n conserve un nombre limité de messages en contexte. Sur des workflows longs avec beaucoup d'interactions, l'orchestrateur peut "oublier" des décisions prises en début de session. Pour les processus critiques, la source de vérité doit toujours être Airtable, pas la mémoire de conversation.
Le pattern "Typing Action + Message Patience" (nœuds Telegram qui envoient un indicateur de frappe pendant que l'agent travaille) change fondamentalement l'expérience utilisateur. Sans ça, 8 secondes de silence sur Telegram semblent une éternité. Avec l'indicateur de frappe, ça semble naturel.
Chaque règle absolue du system prompt devrait aussi exister comme commentaire dans le workflow n8n. Le system prompt peut changer ; les nœuds de filtrage représentent des invariants durs qui ne dépendent pas du LLM.

Ingénieur diplômé de l'ESIEA, 15 ans d'expérience sur des plateformes MFT en production — Axway B2Bi, Gateway, Integrator, CFT. Passé par l'AIFE, Groupama, Arval BNP Paribas et SFR Distribution. Actuellement en exploration de l'intersection entre middleware industriel et IA agentique.
At Lazard Frères Gestion, we operate 65 active MFT partners in production. Around twenty use SFTP with SSH key authentication — the rest use FTPS with certificates, or proprietary protocols. Our CISO/security policy mandates a compulsory annual rotation of all SFTP keys. No exceptions. No waivers.
The process as it existed before: identify the impacted partners in a spreadsheet, draft an email to each one with the new public key generated manually, wait for their confirmation (and follow up if they go silent), manually update Axway B2Bi, and record the status in the tracker. Simple on paper. In practice: 4 hours per rotation on average, confirmations that drag on, follow-ups that get missed, and statuses that are never up to date when you actually need them to be.
Worse: the whole process depends entirely on a single person being available. If that person is on leave during a critical rotation window, everything stops. There is no system memory. Everything lives in people’s heads and in email threads.
I chose n8n as the low-level orchestrator for one very specific reason: the ability to build autonomous sub-workflows connected together, with a level of control that platform-as-a-service solutions don’t offer easily. Claude AI runs inside each agent as the LLM backbone via @n8n/n8n-nodes-langchain.lmChatAnthropic.
The architecture consists of two main workflows and four specialized agents invoked as sub-workflows:
What makes this architecture robust: no agent acts alone. The orchestrator always decides. Agents are just arms — they execute discrete tasks and bring results back. This is a fundamental distinction versus a classic “agent loop” architecture where the agent would make its own decisions end-to-end.
The main workflow has three distinct entry points that converge into the same orchestrator:
scheduleTrigger node fires every morning at 8:00. The Set Trigger Auto node automatically builds the input message: "Date: [day] — daily automated scan — check all SFTP keys and trigger the required actions." From there, the orchestrator runs fully autonomously.This is one of the sharpest architectural details in the project. Before you engage the heavy Claude Sonnet orchestrator for every Telegram message, a lightweight agent powered by Claude Haiku 4.5 categorizes the message into a single value: "simple" or "complex".
If simple → direct reply, no tool calls, near-zero latency. If complex → route to the full orchestrator with all agents. This Classifier → Router pattern drastically reduces inference costs and latency for everyday interactions (“Are we good for Acme Corp?” → 1 second instead of 8).
Pattern to keep: using a lightweight model as a gate before a powerful model is one of the most effective optimizations in multi-agent systems. A Haiku call costs roughly ~20x less than a Sonnet call. For dozens of daily interactions, it adds up.
HITL (Human In The Loop) is the cornerstone of the system from a security standpoint. No B2Bi activation can happen without prior human validation. This isn’t a “nice-to-have” — it’s hardcoded in the orchestrator’s system prompt as an absolute rule.
I chose simultaneous dual-channel validation. The logic: maximize the chance of a quick response, regardless of where the validator is.
MFT-YYYYMMDD-HHMMSS (regex /MFT-\d{8}-\d{6}/i), and a direct validation link. The CISO gets the full context for an informed decision.resume webhook. The second is ignored. No double-validation on the same token.Critical rule discovered in testing: after HITL validation by email (token YES), the orchestrator must not trigger another HITL on Telegram. There is one and only one validation required. I had to state it explicitly in the system prompt after running into double-validation loops during early tests.
All governance rests on one Airtable table: SFTP_Partners. It is the system’s persistent memory — every agent reads and writes to it. No state exists outside of it.
| # | Partner | Expiry date | Status | Email sent date | Confirmation date | B2Bi activation date | Follow-ups | Conversation notes |
|---|---|---|---|---|---|---|---|---|
| 1 | Acme Corp | 15/9/2026 | New | — | — | — | 0 | — |
| 2 | Beta Solutions | 20/8/2024 | Pending | 2/6/2024 | — | — | 1 | Waiting for partner confirmation. |
| 3 | Gamma Industries | 10/7/2027 | Activated | 25/2/2026 | — | — | 0 | 2026-02-25 — Confirmation email received |
| 4 | Delta Partners | 1/10/2024 | Active | 4/6/2024 | 6/6/2024 | 7/6/2024 | 0 | Smooth process. |
| 9 | Iota Consulting | 18/7/2024 | Escalated | 8/6/2024 | — | — | 3 | Third follow-up. [2026-02-24] Escalated to CISO. |
Status follows a strict state machine: New → Email sent → Pending → Partner confirmed → Activated. A status cannot move backwards (except via manual correction). Escalation is a terminal state and requires human intervention to resolve.
{name: "Activated"} — not a direct string. All comparisons must use .name.This is the most sophisticated workflow in terms of filtering logic. Every received email must be categorized and routed to the right handler — without ever triggering a stray action on an internal email, an auto-reply, or an unrelated message.
The workflow processes incoming emails through a cascade filter pipeline before passing them to the orchestrator:
This filtering pipeline is essential. Without it, the orchestrator would receive out-of-office emails as partner confirmations, and internal validation tokens as technical questions. I learned that the hard way during early tests.
HITL token detection deserves special attention. The filter uses two OR conditions: the token can appear in the subject or in the body (regex /MFT-\d{8}-\d{6}/i). Some email clients rewrite the subject line on reply — you must cover both.
Once filtered, each incoming email from a known partner goes to the email orchestrator, which determines the nature of the reply and triggers the right action:
The part I wish I had read before starting. Each bug below represents anywhere from 30 minutes to half a day of debugging.
Airtable Single Select returns {name: "Confirmed", color: "..."}, not the string "Confirmed" directly. Every comparison like === "Confirmed" fails silently — no error, just conditions that never trigger.
This impacted 3 different condition nodes in the workflow. All Airtable Single Select fields behave the same way.
Telegram messages containing French accented characters (é, è, ç, à, ù) caused Telegram API parsing errors like "Can't parse message: byte offset N". Telegram expects clean UTF-8, but some encodings in n8n introduce control characters.
The Merge node that was supposed to wait for both HITL channels (email + Telegram) would fire as soon as one channel replied, without waiting for the other. Result: the workflow continued with incomplete data or processed the same validation twice.
The Gmail Trigger was catching emails sent by the workflow itself — especially “Re: SFTP key rotation” replies to partners. The orchestrator ended up analyzing its own messages as if they were partner replies, creating infinite loops.
After receiving a validation email with token YES, the Email Orchestrator would sometimes trigger the HITL Agent again “to confirm on Telegram too”. This behavior wasn’t in code — it was in the LLM’s reasoning: it inferred that two validations were better than one.
Lesson: what feels obvious to a human must be written explicitly for an autonomous decision-making LLM.
I added Airtable fields as needs emerged during development. Some computed formulas referenced field names that had been renamed in the meantime. Airtable formula errors don’t propagate as exceptions in n8n — they just return null values.
Telegram voice messages cannot be transcribed directly from the URL provided by the trigger — the URL expires very quickly. You must first download the audio file with a dedicated Telegram node, then pass the binary to Whisper for transcription.
The main orchestrator’s system prompt includes a section of absolute rules that must never be overridden by user input. This is the system’s safety zone.
I should have designed the full Airtable schema before writing a single workflow node. Adding fields as I went caused Bug #6 and cost me two days of refactoring. The rule: model every possible partner state before coding any transition.
Bug #5 taught me something important: what feels obvious to a human (“one validation is enough”) must be written explicitly into the system prompt. An autonomous reasoning LLM can easily decide that two validations are better than one — and from its perspective that inference is perfectly valid. Prompt precision is everything.
The first real triggers revealed three bugs at once. A dedicated test environment with dummy partners (Airtable rows with test email addresses) is mandatory. Also: test Gmail filters using emails sent from different clients to cover encoding edge cases.
The memoryBufferWindow in n8n keeps only a limited number of messages in context. On long workflows with many interactions, the orchestrator can “forget” decisions made early in the session. For critical processes, Airtable must always be the source of truth — not conversation memory.
The “Typing Action + Message Patience” pattern (Telegram nodes that send a typing indicator while the agent is working) fundamentally changes the UX. Without it, 8 seconds of silence on Telegram feels endless. With it, it feels natural.
Every absolute rule in the system prompt should also exist as a comment in the n8n workflow. Prompts can change; filtering nodes represent hard invariants that shouldn’t depend on the LLM.

ESIEA graduate engineer, 15 years of experience running production MFT platforms — Axway B2Bi, Gateway, Integrator, CFT. Previously at AIFE, Groupama, Arval BNP Paribas and SFR Distribution. Currently exploring the intersection of industrial middleware and agentic AI.