MFT & Middleware · IA & Automatisation · Architecture · Retour d'expérience

J'ai automatisé la rotation des clés SFTP
avec N8N & Claude AI — architecture complète.

Au moins 65 rotations par an — une par partenaire, parfois plus. 65 partenaires. Une politique RSSI qui ne transige pas. Et une équipe MFT qui faisait tout ça à la main depuis des années. J'ai construit un système multi-agents n8n + Claude AI avec validation humaine double canal. Voici l'architecture complète, les prompts système, les bugs réels, et ce que j'ai appris.

Photo de profil
Ismail Bouchkhi
Consultant Expert MFT · Lazard Frères · Paris
Fév 2026  ·  20 min de lecture
"Chaque année, la même chose : des emails à envoyer, des confirmations à attendre, des clés à déployer, des statuts à mettre à jour. 4 heures de travail manuel par rotation. Multipliez par 65 partenaires. 100 heures par an sur une tâche qui ne demande aucune intelligence — mais qui demande une attention absolue. J'ai voulu voir si l'IA pouvait changer ça sans enlever l'humain des décisions critiques."

Le problème à 100 heures par an

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.

65
Partenaires MFT actifs
25
Rotations / an
4h
Temps moyen manuel
~100h
Coût annuel estimé

Architecture multi-agents — vue d'ensemble

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 :

MFT_KEY_GOVERNANCE — Architecture globale
⏰ Scheduler 8h00
Déclenchement quotidien
→ Set Trigger Auto
+
📱 Telegram Trigger
Commande manuelle
Text + Voice (Whisper)
+
📧 Gmail Trigger
Réponses partenaires
Tokens HITL · Auto-reply
↓ convergent vers ↓
🤖 Orchestrateur MFT (Claude Sonnet)
Cerveau central — reçoit le contexte, décide des actions, distribue aux agents
Règles absolues · Mémoire fenêtrée · Format réponse strict
↓ appelle ↓
🔧 Technical Agent
Scan Airtable
Statuts · B2Bi sim
Logging Notes
📧 Communication Agent
Emails partenaires
Analyse réponses
Relances J+3/J+7
👤 HITL Agent
Validation double canal
Email + Telegram
Token unique
📅 Calendar Agent
Rappels J+3
Événements activation
Escalade J+7

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.

Workflow 1 — Main Orchestrator

Le workflow principal a trois points d'entrée distincts qui convergent vers le même orchestrateur :

Entrée 01
⏰ Scheduler Quotidien 8h00
Un nœud 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.
Entrée 02
📱 Telegram Trigger — Message reçu
L'équipe MFT peut interagir en langage naturel via Telegram. Le workflow supporte texte et messages vocaux — les recordings sont transcrits en temps réel via OpenAI Whisper avant d'être transmis à l'orchestrateur. Avant même d'atteindre le vrai agent, un Classifier LLM (Claude Haiku 4.5) détermine si le message est "simple" ou "complexe".
Entrée 03
🔄 Restore Input
Entrée programmatique pour les reprises de workflow après attente — par exemple lorsque le système reprend après validation HITL ou réception d'une réponse partenaire. Permet de maintenir le contexte entre deux exécutions distinctes.
n8n — Main Orchestrator workflow overview
Capture n8n : Workflow 1 — Main Orchestrator (Telegram + Scheduler + Restore Input → Orchestrateur MFT). n8n snapshot: Workflow 1 — Main Orchestrator (Telegram + Scheduler + Restore Input → MFT Orchestrator).

Le Classifier — simple ou complexe ?

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".

Classifier Agent — System Prompt
"Tu reçois un message. Réponds UNIQUEMENT par : - "simple" si c'est une salutation, question courte, remerciement, ou message ne nécessitant aucune action externe - "complexe" si c'est une demande qui nécessite d'envoyer un email, chercher des infos, gérer un agenda, faire une recherche web, accéder à des fichiers ou une base de données Ne réponds rien d'autre que "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 — validation humaine double canal

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.

HITL — Les deux canaux
  • Canal email : notification structurée complète avec résumé de la rotation, détails du partenaire, token unique au format 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.
  • Canal Telegram : alerte courte (max 100 caractères, sans accents pour éviter les erreurs byte offset) avec boutons inline Approuver / Refuser. Taillé pour une validation en mobilité, en quelques secondes.
  • Règle de priorité : le premier canal à répondre déverrouille le webhook resume. Le second est ignoré. Pas de double validation possible sur le même token.
  • Timeout : si aucune réponse sous 24h, le système escalade automatiquement avec notification RSSI par email.
Séquence HITL complète
HITL Agent reçoit : { partner: "Acme Corp", b2bi_id: "ACC-001", key_hash: "SHA256:..." }Email RSSI : objet: "MFT-20260225-143022 — Validation rotation Acme Corp" Telegram : "Validation en cours pour Acme Corp ACC-001" ← max 100 charsWebhook wait : workflow suspendu — attend signal resume Timeout : 24h → escalade automatiqueSi APPROUVÉ (email token OUI ou Telegram Approuver) :Technical Agent : simulation B2Bi + statut "Activé" dans AirtableCommunication Agent : email confirmation au partenaireTelegram info : "✅ Acme Corp activé"Si REFUSÉ :Statut : "Bloqué RSSI" dans AirtableEmail partenaire : notification report de la rotation
⚠️

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.

Airtable — la source de vérité unique

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.

MFT_KEY_GOVERNANCE · SFTP_Partners
# 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/20246/6/20247/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.

Champs critiques
  • Statut (Single Select) : c'est le champ qui a causé le Bug #1. Il retourne un objet {name: "Activé"} — pas une string directe. Toutes les comparaisons doivent utiliser .name.
  • Notes échange (Long Text) : journal horodaté de chaque action. L'orchestrateur y appende systématiquement ses actions via Technical Agent. Aucune action sans trace.
  • Nombre relances (Number) : incrémenté à chaque relance. Trigger d'escalade à 3.
  • Date activation B2Bi (Date) : renseignée uniquement après validation HITL et simulation B2Bi réussie.

Workflow 2 — Gmail Trigger & Email Router

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 :

Gmail Trigger — écoute tous les emails entrants
Filter — Internal RSSI — si From === rssi@gmail.com → Ignore (email interne)
Filter — HITL Token — si subject ou body contient /MFT-\d{8}-\d{6}/i → route vers validation token
Filter — No-reply & Auto-reply — regex multi-critères :
  → noreply|no-reply|donotreply|mailer-daemon|postmaster|auto-reply
  → subject: Auto:|Out of office|Absence du bureau|Réponse automatique
  → headers: x-autoreply ou auto-submitted présents
Airtable — Find Partner — lookup par adresse email expéditeur
Filter — Known Partner — si pas de résultat Airtable → Telegram alert "Unknown sender"
Build Orchestrator Context — construit le contexte : snippet, From, Subject
🤖 Orchestrateur Email — Claude Sonnet analyse et agit
n8n — Gmail Trigger & Email Router workflow overview
Capture n8n : Workflow 2 — Gmail Trigger & Email Router (filtres en cascade → Orchestrateur Email). n8n snapshot: Workflow 2 — Gmail Trigger & Email Router (cascade filters → Email Orchestrator).

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.

Le system prompt de l'Email Orchestrateur

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 :

Email Orchestrateur — Logique de décision
Analyse email reçu : De : {{ emailFrom }} Objet : {{ emailSubject }} Contenu : {{ snippet }} ↓ → CONFIRMATION partenaire (clé intégrée, ok, reçu) : Technical Agent → statut "Confirmé partenaire" dans Airtable HITL Agent → validation interne email + token unique STOP → ne pas aller plus loin, attendre HITL ↓ → RÉPONSE TOKEN OUI (token validé avec succès) : ⚠️ C'EST LA SEULE ET UNIQUE VALIDATION REQUISE ⚠️ NE PAS re-déclencher HITL ou confirmation Telegram Technical Agent → statut "Activé" + simulation B2Bi Axway Communication → email confirmation au partenaire Telegram → ✅ info uniquement (pas de question) ↓ → QUESTION technique du partenaire : Communication → réponse email adaptée Technical Agent → log dans Notes échange ↓ → PROBLÈME ou refus : Communication → accusé réception + transmission RSSI Technical Agent → statut "Bloqué" + log Telegram → alerte immédiate RSSI

Les 7 bugs qui m'ont coûté du temps

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.

Bug #1 — Airtable
Single Select retourne un objet, pas une string

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.

// ❌ Avant — échoue silencieusement if (status === "Confirmé") { ... } // ✅ Après — correct if (status?.name === "Confirmé") { ... }

Ce bug a affecté 3 nœuds de condition différents dans le workflow. Tous les champs Single Select Airtable sont concernés.

Bug #2 — Telegram
Erreurs byte offset sur les caractères accentué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.

// Nœud Code dédié avant chaque envoi Telegram const clean = (str) => str .normalize('NFD') .replace(/[\u0300-\u036f]/g, '') // supprime diacritiques .replace(/[^\x00-\x7F]/g, ''); // supprime tout non-ASCII return { text: clean(input.text) };
Bug #3 — n8n Merge Node
Le Merge se déclenchait sur le premier canal seulement

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.

// Configuration correcte du Merge node Mode: "Wait for all inputs" Timeout second input: 24h Behavior on timeout: "Continue with available"
Bug #4 — Gmail Loop
L'agent lisait ses propres emails sortants

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.

// Filter ajouté dans Gmail Trigger Label: FROM_ADDRESS ne contient pas [adresse système] + Filter — No-reply: exclut subject commençant par "Re:" + Filter — Internal RSSI: exclut l'adresse email RSSI interne
Bug #5 — HITL Double-Validation
L'orchestrateur re-déclenchait un HITL après validation email

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.

// Règle ajoutée explicitement dans le system prompt : "RÉPONSE TOKEN OUI → C'EST LA SEULE ET UNIQUE VALIDATION REQUISE NE PAS déclencher de nouveau HITL ou confirmation Telegram NE PAS appeler Human In The Loop une seconde fois"

Moral de l'histoire : ce qui semble évident pour un humain doit être écrit explicitement pour un LLM qui prend des décisions autonomes.

Bug #6 — Airtable Schema
Formules cassées après ajout de champs à la volée

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.

// Bonne pratique : versionner le schéma Airtable // Avant tout ajout de champ : // 1. Documenter les impacts sur les formules existantes // 2. Tester tous les nœuds Airtable après modification // 3. Utiliser des noms de champs stables et non-ambigus
Bug #7 — Telegram Voice
Messages vocaux sans téléchargement préalable du fichier

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.

// Séquence correcte pour voice messages : 1. Telegram Trigger → capte file_id du voice message 2. Download Voice File (nœud Telegram) → télécharge le binaire 3. Switch: Voice or Text → branch selon type de message 4. Transcribe recording (OpenAI Whisper) → texte 5. Text Input (Set) → uniformise avec messages texte

Les règles absolues de l'orchestrateur

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.

R1
Toujours scanner Airtable via Technical Agent avant toute action. Aucune action sur un partenaire sans vérification préalable de son statut actuel. Évite les doublons et les actions hors-contexte.
R2
Ne jamais envoyer deux fois le même email le même jour au même partenaire. Le Technical Agent vérifie la date du dernier email envoyé avant tout envoi.
R3
Toujours logger chaque action dans le champ Notes échange. Chaque action de chaque agent est horodatée et appendée au journal partenaire. Traçabilité totale.
R4
Toujours passer par Human In The Loop avant toute activation B2Bi. Sans exception. Même si le partenaire a confirmé par email, même si le token est valide — le HITL est obligatoire.
R5
Escalader si plus de 2 relances sans réponse. J+3 première relance, J+7 escalade automatique avec notification RSSI. Le statut passe à "Escalade" et requiert intervention humaine.
R6
Les rapports RSSI ne sont jamais envoyés sur Telegram. Telegram reçoit uniquement des confirmations courtes (max 100 caractères) et des demandes OUI/NON. Tout rapport détaillé va par email uniquement.
R7
Après envoi d'email, terminer le workflow immédiatement. Ne pas attendre la réponse dans le workflow courant — elle arrivera via le Gmail Trigger séparé. Cette règle est critique pour éviter les timeouts et les exécutions pendantes.
« L'IA ne remplace pas l'ingénieur MFT. Elle lui redonne du temps pour les décisions qui demandent vraiment son expertise — et elle n'oublie jamais de relancer. »

Ce que j'ai appris en construisant ça

1. Le schéma de données d'abord

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.

2. Les LLMs prennent des décisions surprenantes

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.

3. Tester avec de faux partenaires d'abord

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.

4. La mémoire fenêtrée a ses limites

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.

5. La latence perçue compte

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.

6. Documenter les invariants dans le code

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.

#MFT#n8n#ClaudeAI#SFTP#Axway#Airtable#HITL#Automatisation#Sécurité#MultiAgents#LangChain#GmailTrigger#Telegram#B2Bi
Photo de profil
Ismail Bouchkhi
Consultant Expert MFT · Lazard Frères · ESIEA Paris

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.

MFT & Middleware · AI & Automation · Architecture · Field notes

I automated SFTP key rotation
with n8n & Claude AI — full architecture.

At least 65 rotations per year — one per partner, sometimes more. 65 partners. A security policy that doesn’t compromise. And an MFT team that had been doing all of it by hand for years. I built a multi-agent n8n + Claude AI system with dual-channel human validation. Here’s the full architecture, the system prompts, the real bugs, and what I learned.

Photo de profil
Ismail Bouchkhi
Senior MFT Consultant · Lazard Frères · Paris
Feb 2026  ·  20 min read
"Every year, it’s the same story: emails to send, confirmations to wait for, keys to deploy, statuses to update. 4 hours of manual work per rotation. Multiply that by 25 partners. 100 hours a year spent on a task that requires zero intelligence — but demands absolute attention. I wanted to see if AI could change that without removing humans from critical decisions."

The 100-hours-a-year problem

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.

65
Active MFT partners
25
Rotations / year
4h
Avg manual time
~100h
Estimated yearly cost

Multi-agent architecture — the big picture

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:

MFT_KEY_GOVERNANCE — Global architecture
⏰ Scheduler 8:00
Daily trigger
→ Set Trigger Auto
+
📱 Telegram Trigger
Manual command
Text + Voice (Whisper)
+
📧 Gmail Trigger
Partner replies
HITL tokens · Auto-reply
↓ converging into ↓
🤖 MFT Orchestrator (Claude Sonnet)
Central brain — receives context, decides actions, delegates to agents
Non-negotiable rules · Windowed memory · Strict response format
↓ calls ↓
🔧 Technical Agent
Scan Airtable
Statuses · B2Bi sim
Notes logging
📧 Communication Agent
Partner emails
Reply analysis
Follow-ups D+3/D+7
👤 HITL Agent
Dual-channel validation
Email + Telegram
Unique token
📅 Calendar Agent
D+3 reminders
Activation events
D+7 escalation

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.

Workflow 1 — Main Orchestrator

The main workflow has three distinct entry points that converge into the same orchestrator:

Entry 01
⏰ Daily Scheduler 8:00
A 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.
Entry 02
📱 Telegram Trigger — incoming message
The MFT team can interact in natural language via Telegram. The workflow supports text and voice messages — recordings are transcribed in real time via OpenAI Whisper before being sent to the orchestrator. Before the “big” agent even gets involved, a Classifier LLM (Claude Haiku 4.5) determines whether the message is “simple” or “complex”.
Entry 03
🔄 Restore Input
A programmatic entry point for resuming a workflow after a wait — for example, when the system continues after HITL validation or after receiving a partner reply. It lets you preserve context across separate executions.
n8n — Main Orchestrator workflow overview
Capture n8n : Workflow 1 — Main Orchestrator (Telegram + Scheduler + Restore Input → Orchestrateur MFT). n8n snapshot: Workflow 1 — Main Orchestrator (Telegram + Scheduler + Restore Input → MFT Orchestrator).

The Classifier — simple or complex?

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".

Classifier Agent — System Prompt
"You receive a message. Reply ONLY with: - "simple" if it’s a greeting, a short question, a thank-you, or anything that requires no external action - "complex" if it’s a request that requires sending an email, searching for info, managing a calendar, doing web research, accessing files or a database Do not reply with anything other than "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 — dual-channel human validation

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.

HITL — the two channels
  • Email channel: a complete structured notification with a rotation summary, partner details, a unique token in the format 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.
  • Telegram channel: a short alert (max 100 characters, no accented characters to avoid byte-offset errors) with inline Approve / Reject buttons. Built for quick validation on the go.
  • Priority rule: the first channel that replies unlocks the resume webhook. The second is ignored. No double-validation on the same token.
  • Timeout: if there’s no response within 24h, the system automatically escalates with an email notification to the CISO.
Full HITL sequence
HITL Agent receives: { partner: "Acme Corp", b2bi_id: "ACC-001", key_hash: "SHA256:..." }CISO email: subject: "MFT-20260225-143022 — Validate rotation for Acme Corp" Telegram: "Validation pending for Acme Corp ACC-001" ← max 100 charsWebhook wait: workflow suspended — waiting for resume signal Timeout: 24h → automatic escalationIf APPROVED (email token YES or Telegram Approve):Technical Agent: B2Bi simulation + Airtable status "Activated"Communication Agent: confirmation email to partnerTelegram info: "✅ Acme Corp activated"If REJECTED:Status: "Blocked (CISO)" in AirtablePartner email: rotation postponed notification
⚠️

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.

Airtable — the single source of truth

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.

MFT_KEY_GOVERNANCE · SFTP_Partners
# 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/20246/6/20247/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.

Critical fields
  • Status (Single Select): this is what caused Bug #1. It returns an object {name: "Activated"} — not a direct string. All comparisons must use .name.
  • Conversation notes (Long Text): a timestamped log of every action. The orchestrator always appends to it via the Technical Agent. No action without a trace.
  • Follow-up count (Number): incremented on each reminder. Escalation triggers at 3.
  • B2Bi activation date (Date): filled only after HITL approval and a successful B2Bi simulation.

Workflow 2 — Gmail Trigger & Email Router

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:

Gmail Trigger — listens to all incoming emails
Filter — Internal CISO — if From === rssi@gmail.com → Ignore (internal email)
Filter — HITL Token — if subject/body contains /MFT-\d{8}-\d{6}/i → route to token validation
Filter — No-reply & Auto-reply — multi-criteria regex:
  → noreply|no-reply|donotreply|mailer-daemon|postmaster|auto-reply
  → subject: Auto:|Out of office|Absence du bureau|Automatic reply
  → headers: x-autoreply or auto-submitted present
Airtable — Find Partner — lookup by sender email address
Filter — Known Partner — if no Airtable match → Telegram alert "Unknown sender"
Build Orchestrator Context — builds context: snippet, From, Subject
🤖 Email Orchestrator — Claude Sonnet analyzes and acts
n8n — Gmail Trigger & Email Router workflow overview
Capture n8n : Workflow 2 — Gmail Trigger & Email Router (filtres en cascade → Orchestrateur Email). n8n snapshot: Workflow 2 — Gmail Trigger & Email Router (cascade filters → Email 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.

The Email Orchestrator’s system prompt

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:

Email Orchestrator — decision logic
Analyze incoming email: From: {{ emailFrom }} Subject: {{ emailSubject }} Content: {{ snippet }} ↓ → PARTNER CONFIRMATION (key integrated, ok, received): Technical Agent → set Airtable status "Partner confirmed" HITL Agent → internal validation email + unique token STOP → do not go further, wait for HITL ↓ → TOKEN YES REPLY (token successfully validated): ⚠️ THIS IS THE ONE AND ONLY VALIDATION REQUIRED ⚠️ DO NOT re-trigger HITL or Telegram confirmation Technical Agent → status "Activated" + Axway B2Bi simulation Communication → confirmation email to partner Telegram → ✅ info only (no question) ↓ → PARTNER TECHNICAL QUESTION: Communication → tailored email response Technical Agent → log in Conversation notes ↓ → ISSUE or REFUSAL: Communication → acknowledgment + forward to CISO Technical Agent → status "Blocked" + log Telegram → immediate CISO alert

The 7 bugs that cost me time

The part I wish I had read before starting. Each bug below represents anywhere from 30 minutes to half a day of debugging.

Bug #1 — Airtable
Single Select returns an object, not a string

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.

// ❌ Before — silently fails if (status === "Confirmed") { ... } // ✅ After — correct if (status?.name === "Confirmed") { ... }

This impacted 3 different condition nodes in the workflow. All Airtable Single Select fields behave the same way.

Bug #2 — Telegram
Byte offset errors on accented characters

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.

// Dedicated Code node before each Telegram send const clean = (str) => str .normalize('NFD') .replace(/[\u0300-\u036f]/g, '') // remove diacritics .replace(/[^\x00-\x7F]/g, ''); // remove all non-ASCII return { text: clean(input.text) };
Bug #3 — n8n Merge Node
Merge triggered on the first channel only

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.

// Correct Merge node configuration Mode: "Wait for all inputs" Timeout second input: 24h Behavior on timeout: "Continue with available"
Bug #4 — Gmail Loop
The agent was reading its own outgoing emails

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.

// Filters added to Gmail Trigger Label: FROM_ADDRESS does not contain [system address] + Filter — No-reply: exclude subjects starting with "Re:" + Filter — Internal CISO: exclude internal CISO email address
Bug #5 — HITL Double Validation
The orchestrator re-triggered HITL after email validation

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.

// Rule added explicitly in the system prompt: "TOKEN YES REPLY → THIS IS THE ONE AND ONLY VALIDATION REQUIRED DO NOT trigger HITL again DO NOT call Human In The Loop a second time"

Lesson: what feels obvious to a human must be written explicitly for an autonomous decision-making LLM.

Bug #6 — Airtable Schema
Formulas broke after adding fields on the fly

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.

// Best practice: version your Airtable schema // Before adding any field: // 1. Document impacts on existing formulas // 2. Test all Airtable nodes after modification // 3. Use stable, unambiguous field names
Bug #7 — Telegram Voice
Voice messages require downloading the file first

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.

// Correct sequence for voice messages: 1. Telegram Trigger → capture file_id of the voice message 2. Download Voice File (Telegram node) → download binary 3. Switch: Voice or Text → branch by message type 4. Transcribe recording (OpenAI Whisper) → text 5. Text Input (Set) → normalize with text messages

The orchestrator’s non-negotiable rules

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.

R1
Always scan Airtable via the Technical Agent before any action. No action on a partner without verifying the current status first. Prevents duplicates and out-of-context actions.
R2
Never send the same email twice on the same day to the same partner. The Technical Agent checks the last sent date before any send.
R3
Always log every action in the Conversation notes field. Every action from every agent is timestamped and appended. Full traceability.
R4
Always go through Human In The Loop before any B2Bi activation. No exceptions. Even if the partner confirmed by email, even if the token is valid — HITL is mandatory.
R5
Escalate after more than 2 follow-ups without a reply. D+3 first follow-up, D+7 automatic escalation with CISO email notification. Status switches to "Escalated" and requires human intervention.
R6
CISO reports are never sent on Telegram. Telegram gets only short confirmations (max 100 characters) and YES/NO requests. Detailed reporting is email-only.
R7
After sending an email, end the workflow immediately. Don’t wait for a reply inside the current run — it will come through the separate Gmail Trigger workflow. This rule is critical to avoid timeouts and hanging executions.
“AI doesn’t replace the MFT engineer. It gives them time back for decisions that truly require expertise — and it never forgets to follow up.”

What I learned building this

1. Data schema first

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.

2. LLMs make surprising decisions

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.

3. Test with fake partners first

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.

4. Windowed memory has limits

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.

5. Perceived latency matters

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.

6. Document invariants in the workflow

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.

#MFT#n8n#ClaudeAI#SFTP#Axway#Airtable#HITL#Automation#Security#MultiAgents#LangChain#GmailTrigger#Telegram#B2Bi
Photo de profil
Ismail Bouchkhi
Senior MFT Consultant · Lazard Frères · ESIEA Paris

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.