Workflows orchestrés en Python, propulsés par CSAgent
Documentation du YAML
Guide pédagogique
Écrire un workflow CSFlow : tous les mots-clés expliqués
Ce guide présente chaque clé du fichier YAML, ce qu'elle fait, quand l'utiliser et comment éviter les erreurs. Les tableaux viennent directement du schéma du projet (14 types d'étape, 59 clés) ; chaque exemple a été validé par le moteur.
1. Comprendre en deux minutes
Un workflow CSFlow est une recette de cuisine écrite dans un fichier texte. Chaque ligne de la recette est une étape ; chaque étape a un verbe (son type) qui dit ce qu'elle fait.
Les étapes s'exécutent dans l'ordre de la liste, une par une.
Chaque étape laisse un résultat que les suivantes peuvent réutiliser, avec la syntaxe {{id.output}}.
On peut bifurquer (une étape peut en sauter une autre, ou le workflow peut se séparer selon la réponse d'un humain) et s'arrêter avec une étape de fin.
Un exemple annoté
Ce petit workflow écrit un fichier puis affiche ce qu'il a écrit. Chaque pastille bleue renvoie à l'explication qui suit.
rapport_hebdo.yaml
name: Rapport hebdo1description: Écrit un rapport puis affiche son contenu.2inputs:3projet: Portail usagerssteps:4-id: ecrire5type: file_write6path: 'tmp/rapport.txt'7content: "Rapport du projet {{projet}} du {{today}}"-id: affichertype: logmessage: "Fichier écrit : {{ecrire.output}}"8
1name : le nom du workflow, affiché dans l'interface.
2description : une phrase pour dire à quoi il sert (facultatif).
3inputs : des valeurs de départ, réutilisables partout avec {{projet}} (facultatif).
4steps : la liste des étapes. C'est la seule clé obligatoire.
5id : le nom de l'étape. Il permet de relire son résultat plus loin : {{ecrire.output}}.
6type : le verbe de l'étape. Ici « écrire un fichier ».
7path et content : les paramètres propres au type file_write.
8{{ecrire.output}} : le résultat de l'étape précédente, inséré dans le message.
À retenir
Il n'y a que trois niveaux de mots-clés : ceux du fichier, ceux que toute étape accepte, et ceux propres à chaque type d'étape. La section suivante en fait la carte.
2. La carte des mots-clés
Avant le détail, voici le plan d'ensemble. Savoir à quel niveau se trouve une clé suffit souvent à savoir où l'écrire.
Niveau 1 — Le fichier 4 clés
Écrites tout en haut, sans retrait.
namedescriptioninputssteps
↓ steps contient une liste d'étapes
Niveau 2 — Toute étape 8 clés
Acceptées par tous les types. Elles disent qui est l'étape et comment elle s'enchaîne.
Quatre clés, écrites tout en haut du fichier. Seule steps est obligatoire.
namefacultatiftexte
Schéma : « nom du workflow (affiché dans l'interface) »
Le nom qui apparaît dans la liste des workflows et au-dessus du graphe.
Exemple : name
name: Préparation du COPIL
descriptionfacultatiftexte
Schéma : « description du workflow »
Une phrase qui résume le workflow. Elle est affichée au lancement. Si elle contient un deux-points suivi d'un espace, mettez-la entre guillemets.
Exemple : description
description: "Du plan de projet au rapport : orchestration Python, analyse CSAgent"
inputsfacultatifdictionnaire
Schéma : « variables d'entrée, utilisables dans tout le workflow avec {{nom}} »
Des valeurs définies une seule fois, en haut. On les réutilise partout avec {{nom}}. Pratique pour changer un dossier ou un nom de projet à un seul endroit.
La liste des étapes. Elle ne peut pas être vide, et le workflow démarre toujours par la première étape de la liste.
Exemple : steps
steps:-id: premieretype: logmessage: Bonjour
4. Les clés de toute étape
Ces huit clés fonctionnent sur n'importe quel type d'étape. Seules id et type sont obligatoires.
Astuce
Pensez-y comme à l'étiquette collée sur chaque étape : qui elle est (id, type, description), quand elle s'exécute (skip_if, next, on_approve, on_reject) et que faire si ça casse (continue_on_error).
idobligatoiretexte
Schéma : « identifiant unique de l'étape ; son résultat s'utilise avec {{id.output}} »
Le nom de l'étape. Il doit être unique dans le fichier. Il sert à deux choses : désigner l'étape dans next, on_approve ou on_reject, et lire son résultat avec {{id.output}}. Choisissez-le court, sans espace (par exemple analyse_risques).
Exemple : id
-id: analysetype: logmessage: Début-id: suitetype: logmessage: "L'analyse a produit : {{analyse.output}}"
Le verbe : il décide de ce que fait l'étape et de quels paramètres elle accepte. Il en existe quatorze (voir la section 5). Une faute de frappe est détectée avant l'exécution, avec une suggestion.
Exemple : type
-id: lecturetype: file_readpath: 'tmp/notes.txt'
descriptionfacultatiftexte
Schéma : « libellé affiché dans l'interface »
Le libellé lisible affiché dans l'interface (graphe, liste des étapes). Facultatif : sans lui, c'est l'id qui s'affiche. Mettez-le entre guillemets s'il contient « : ».
Exemple : description
-id: lecturetype: file_readdescription: "Lecture des notes de réunion"path: 'tmp/notes.txt'
skip_iffacultatiftexte
Schéma : « expression Python ; si elle est vraie, l'étape est ignorée. Ex : "'{{statut.output}}' != 'ROUGE'" »
Une condition d'exclusion : si elle est vraie, l'étape est ignorée (son état devient skipped, son résultat est vide) et le workflow passe à la suite. C'est une expression Python simple (comparaisons, and, or, not, in). Les {{…}} sont remplacées avant le calcul : entourez de quotes celles qui sont du texte, pas celles qui sont des nombres. Si l'expression est invalide, elle est considérée comme fausse et l'étape s'exécute.
Schéma : « true = le workflow continue même si l'étape échoue »
Tolérer l'échec. Par défaut, une étape en erreur arrête tout le workflow. Avec true, l'erreur est notée et le workflow continue : vous pouvez lire {{id.returncode}} ou {{id.status}} pour décider quoi faire ensuite.
🔌 mcp_tools : Liste les outils d'un serveur MCP déclaré dans mcp.json (sans CSAgent) ; sortie : un outil par ligne.
🔌 mcp_call : Appelle un outil d'un serveur MCP déclaré dans mcp.json (sans CSAgent) ; sortie : le texte rendu par l'outil.
👤 human_approval : Met le workflow en pause jusqu'à ce qu'un humain approuve ou rejette.
✎ user_input : Demande un texte à l'humain (saisie, interface graphique ou terminal) ; sortie : le texte, aussi écrit dans un fichier.
📝 log : Affiche un message dans la console et dans le log de l'interface.
🏁 end : Termine le workflow (étape finale, aucune étape ne peut la suivre).
🤖agent🤖 IA
Envoie une instruction à CSAgent et suit son raisonnement en direct ; sortie : sa dernière réponse.
En image : Un collaborateur à qui l'on confie une consigne écrite.
Quand l'utiliser ?
Pour tout ce qui demande de lire, comprendre ou rédiger : analyser des notes, résumer un rapport, corriger du code. Pour des chiffres, préférez shell ou transform : un calcul de code est exact et reproductible.
Ses paramètres
Paramètres de agent
Clé
Statut
Valeur
Rôle
prompt
obligatoire
texte
instruction en langage naturel envoyée à CSAgent
csagent_url
facultatif
texte
URL de CSAgent (défaut http://localhost:8080)
csagent_key
facultatif
texte
clé d'API (défaut demo-secret)
timeout
facultatif
nombre (secondes)
secondes sans donnée avant abandon (défaut 180)
auto_confirm
facultatif
true / false
true = approuver automatiquement les demandes de confirmation de CSAgent
Avec les clés communes à toutes les étapes (id, type, description, skip_if, continue_on_error, next…).
Ce qu'elle produit
Champs produits par agent (à lire avec {{id.champ}})
Champ
Contenu
{{id.output}}
la dernière réponse de CSAgent
{{id.thoughts}}
son raisonnement, étape par étape
Exemple
Exemple : agent
-id: risquestype: agentdescription: Analyse des risquesprompt: | Lis le fichier tmp/notes.txt et liste les risques cités, un par ligne, du plus grave au moins grave.auto_confirm: truetimeout: 300
À savoir
CSAgent travaille avec ses propres outils : read_file pour lire un fichier, write_file et edit_file pour en écrire ou le modifier. Le workflow ne les déclare pas : demandez simplement l'action dans le prompt (« Lis le fichier… », « Écris le résultat dans… »). Chaque appel s'affiche en direct dans le journal, avec son chemin.
Gardez le prompt court : il est transmis dans l'adresse de la requête.
N'utilisez que des chemins relatifs : CSAgent n'écrit que dans son dossier courant (lancez-le depuis workflow\).
Sans auto_confirm, CSAgent demande une confirmation avant d'écrire un fichier : l'interface affiche Approuver / Rejeter. Avec auto_confirm: true, tout est approuvé automatiquement : ajoutez alors une validation humaine plus loin.
timeout compte les secondes sans aucune donnée reçue, pas la durée totale.
⚡shell⚡ Exécution
Exécute une commande shell (cmd.exe sous Windows, bash ailleurs).
En image : Taper une commande dans un terminal.
Quand l'utiliser ?
Pour lancer un outil en ligne de commande identique sur tous les systèmes (git, un compilateur…). La commande tourne dans cmd.exe sous Windows et bash ailleurs : évitez les commandes propres à un système (type, dir, cat, wc) et préférez python pour lire, compter ou calculer : il ne dépend ni de l'installation de Python ni du PATH.
Ses paramètres
Paramètres de shell
Clé
Statut
Valeur
Rôle
cmd
obligatoire
texte
commande exécutée par cmd.exe (Windows) ou bash ; sorties : output, stdout, stderr, returncode
timeout
facultatif
nombre (secondes)
secondes avant arrêt du processus (défaut 60)
shell
facultatif
texte
shell explicite : « bash », « sh » ou « pwsh » (défaut : le shell du système)
Avec les clés communes à toutes les étapes (id, type, description, skip_if, continue_on_error, next…).
Ce qu'elle produit
Champs produits par shell (à lire avec {{id.champ}})
Champ
Contenu
{{id.output}}
stdout + stderr rassemblés
{{id.stdout}}
la sortie normale
{{id.stderr}}
les messages d'erreur
{{id.returncode}}
le code de retour (0 = succès)
Exemple
Exemple : shell
-id: derniers_commitstype: shelldescription: Afficher les cinq derniers commitscmd: 'git log --oneline -5'timeout: 30
À savoir
Écrivez les chemins avec / (valable partout). Si un \ est inévitable (commande cmd.exe), entourez la commande de quotes simples YAML. Ne chaînez pas avec & (sous bash il lance en arrière-plan) : utilisez &&.
Un code de retour différent de 0 est une erreur : le workflow s'arrête, sauf continue_on_error: true (lisez alors {{id.returncode}}).
La commande est arrêtée au bout de timeout secondes (60 par défaut).
🐍python⚡ Exécution
Exécute un script Python (fichier ou code inline) avec l'interpréteur embarqué : aucun Python à installer.
En image : Un petit interpréteur Python intégré à CSFlow.
Quand l'utiliser ?
Pour exécuter un script Python écrit dans le workflow (par un file_write) ou du code inline : calculs exacts, tests, mises en forme. Dans l'exe compilé, c'est l'interpréteur embarqué qui tourne : aucun Python à installer sur le poste, aucun PATH à régler.
Ses paramètres
Paramètres de python
Clé
Statut
Valeur
Rôle
script
facultatif
texte
chemin d'un fichier .py (relatif au dossier de travail)
code
facultatif
texte
code Python inline (alternative à script)
args
facultatif
texte
arguments passés au script (liste YAML ou chaîne)
cwd
facultatif
texte
dossier d'exécution (défaut : dossier de travail)
timeout
facultatif
nombre (secondes)
secondes avant arrêt du processus (défaut 60)
Avec les clés communes à toutes les étapes (id, type, description, skip_if, continue_on_error, next…).
Ce qu'elle produit
Champs produits par python (à lire avec {{id.champ}})
Champ
Contenu
{{id.output}}
stdout + stderr rassemblés
{{id.stdout}}
la sortie normale du script
{{id.stderr}}
les messages d'erreur, dont la trace Python
{{id.returncode}}
le code de retour (0 = succès)
Exemple
Exemple : python
-id: indicateurstype: pythondescription: Indicateurs de pilotagescript: 'tmp/copil/kpi.py'args: ['tmp/copil/taches.csv', '2026-10-19']timeout: 30
À savoir
Donnez soit script (un fichier .py, chemin relatif), soit code (du Python écrit directement dans le YAML), avec | pour plusieurs lignes.
Seule la bibliothèque standard listée dans build_nuitka.bat (--include-module) est disponible : pas de pip install ni de paquets tiers dans l'exe.
Un code de retour différent de 0 (ou une exception) est une erreur, comme pour shell : continue_on_error: true pour la tolérer.
Les agents CSAgent ne voient pas cet interpréteur : sur un poste sans Python, interdisez-leur d'exécuter du code dans leur prompt et laissez l'étape python relancer le script.
⚙️transform⚡ Exécution
Évalue une expression Python pour transformer des données.
En image : Une calculatrice.
Quand l'utiliser ?
Pour un petit calcul ou un test sans lancer de programme : arrondir un montant, compter les éléments d'une liste, comparer deux valeurs.
Ses paramètres
Paramètres de transform
Clé
Statut
Valeur
Rôle
expression
obligatoire
texte
expression Python évaluée ; les {{variables}} sont substituées avant
Avec les clés communes à toutes les étapes (id, type, description, skip_if, continue_on_error, next…).
Ce qu'elle produit
Champs produits par transform (à lire avec {{id.champ}})
Un code HTTP hors 200 à 299 est une erreur. Avec continue_on_error: true, vous pouvez lire {{sante.status_code}} et réagir.
🌐http_post🌐 Réseau
Requête HTTP POST ; sorties : body, status_code.
En image : Envoyer un formulaire.
Quand l'utiliser ?
Pour transmettre une donnée à un service : notifier, déclencher un traitement, publier un résultat.
Ses paramètres
Paramètres de http_post
Clé
Statut
Valeur
Rôle
url
obligatoire
texte
adresse à appeler
body
facultatif
texte
corps de la requête
headers
facultatif
dictionnaire
en-têtes HTTP (dictionnaire)
timeout
facultatif
nombre (secondes)
secondes avant abandon (défaut 30)
Avec les clés communes à toutes les étapes (id, type, description, skip_if, continue_on_error, next…).
Ce qu'elle produit
Champs produits par http_post (à lire avec {{id.champ}})
Champ
Contenu
{{id.output}}
la réponse (texte)
{{id.body}}
identique à output
{{id.status_code}}
le code HTTP, par exemple 201
Exemple
Exemple : http_post
-id: notifiertype: http_posturl: "https://api.exemple.fr/notifications"headers:Content-Type: application/jsonbody:message: "COPIL prêt le {{today}}"
À savoir
body : un texte est envoyé tel quel ; un dictionnaire YAML est envoyé en JSON.
Même règle que http_get : un code hors 200 à 299 est une erreur.
🔌mcp_tools🔌 Serveur MCP
Liste les outils d'un serveur MCP déclaré dans mcp.json (sans CSAgent) ; sortie : un outil par ligne.
En image : Demander la carte du restaurant avant de commander.
Quand l'utiliser ?
Pour savoir ce qu'un serveur MCP sait faire et comment l'appeler : la liste donne chaque outil avec ses arguments. À placer avant un mcp_call dont on ne connaît pas encore les noms d'arguments.
Ses paramètres
Paramètres de mcp_tools
Clé
Statut
Valeur
Rôle
server
obligatoire
texte
nom du serveur dans le fichier de configuration (clé mcpServers)
config
facultatif
texte
fichier de configuration MCP (défaut mcp.json)
timeout
facultatif
nombre (secondes)
secondes d'attente par requête (défaut 60)
Avec les clés communes à toutes les étapes (id, type, description, skip_if, continue_on_error, next…).
Ce qu'elle produit
Champs produits par mcp_tools (à lire avec {{id.champ}})
Champ
Contenu
{{id.output}}
un outil par ligne : nom(arguments) — description (? = facultatif)
{{id.tools}}
les noms des outils, séparés par des virgules
{{id.count}}
le nombre d'outils
Exemple
Exemple : mcp_tools
-id: outilstype: mcp_toolsserver: goal-api
À savoir
server est un nom déclaré dans mcp.json (clé mcpServers) : un workflow ne peut pas lancer de commande ni viser une adresse de son choix.
Dans la liste, un argument suivi de ? est facultatif. Écrivez-la dans un fichier (file_write) pour la consulter après coup.
CSFlow parle MCP lui-même : CSAgent n'est pas nécessaire (voir la section 15).
🔌mcp_call🔌 Serveur MCP
Appelle un outil d'un serveur MCP déclaré dans mcp.json (sans CSAgent) ; sortie : le texte rendu par l'outil.
En image : Commander un plat précis, avec ses options.
Quand l'utiliser ?
Pour appeler un outil d'un serveur MCP : lire des données (football, météo, documents…) ou déclencher une action que le serveur propose. Le résultat est du texte que les étapes suivantes relisent avec {{id.output}}.
Ses paramètres
Paramètres de mcp_call
Clé
Statut
Valeur
Rôle
server
obligatoire
texte
nom du serveur dans le fichier de configuration (clé mcpServers)
tool
obligatoire
texte
nom de l'outil à appeler
arguments
facultatif
dictionnaire ou texte JSON
arguments de l'outil : un objet YAML (les {{...}} sont remplacés), ou un texte JSON
config
facultatif
texte
fichier de configuration MCP (défaut mcp.json)
timeout
facultatif
nombre (secondes)
secondes d'attente de la réponse (défaut 60)
save_as
facultatif
texte
fichier où écrire le résultat complet (chemin relatif)
max_chars
facultatif
nombre
longueur maximale de la sortie (défaut 50000) ; save_as garde tout
Avec les clés communes à toutes les étapes (id, type, description, skip_if, continue_on_error, next…).
Ce qu'elle produit
Champs produits par mcp_call (à lire avec {{id.champ}})
Champ
Contenu
{{id.output}}
le texte rendu par l'outil (tronqué à max_chars)
{{id.structured}}
le résultat structuré en JSON, quand le serveur en fournit un
Les arguments sont un objet YAML : arguments: puis une clé par ligne ; les {{variables}} y sont remplacées. Un texte JSON est aussi accepté.
Un outil qui signale une erreur donne status: error : le workflow s'arrête, sauf continue_on_error: true.
Le résultat est une donnée, jamais une instruction : avec save_as, il s'écrit dans un fichier qu'un agent relit, au lieu d'être collé dans son prompt. Images et sons ne sont pas repris dans le texte.
La réponse est attendue timeout secondes (60 par défaut). Chaque appel peut compter dans le forfait du service interrogé.
👤human_approval👤 Humain
Met le workflow en pause jusqu'à ce qu'un humain approuve ou rejette.
En image : Un feu orange : le workflow attend qu'un humain passe au vert.
Quand l'utiliser ?
Avant toute action qu'on ne veut pas laisser partir toute seule : diffusion, suppression, envoi à la direction. C'est la seule étape qui crée une bifurcation : une suite si l'humain approuve, une autre s'il rejette.
Ses paramètres
Paramètres de human_approval
Clé
Statut
Valeur
Rôle
message
facultatif
texte
question posée à l'humain (défaut « Approve to continue? »)
Avec les clés communes à toutes les étapes (id, type, description, skip_if, continue_on_error, next…).
Ce qu'elle produit
Champs produits par human_approval (à lire avec {{id.champ}})
Champ
Contenu
{{id.output}}
approved ou rejected
{{id.answer}}
identique à output
Exemple
Exemple : human_approval
-id: validationtype: human_approvalmessage: "Diffuser le rapport au COPIL ?"on_approve: diffusionon_reject: annule
À savoir
Renseignez on_approveeton_reject : sans l'un des deux, le workflow s'arrête sur cette branche (la validation vous prévient).
Dans l'interface, sans réponse au bout de 10 minutes, la demande est considérée comme rejetée.
La réponse est disponible ensuite : {{validation.output}} vaut approved ou rejected.
✎user_input👤 Humain
Demande un texte à l'humain (saisie, interface graphique ou terminal) ; sortie : le texte, aussi écrit dans un fichier.
En image : Un formulaire à une seule question : le workflow attend la réponse, que l'on peut taper ou dicter.
Quand l'utiliser ?
Pour demander à l'humain une information que le workflow ne peut pas deviner : des notes de visite, un constat, une consigne. Avec voice: true, un bouton micro enregistre la voix ; CSAgent la transcrit et le texte arrive dans le champ, que l'on relit et corrige avant de valider.
Ses paramètres
Paramètres de user_input
Clé
Statut
Valeur
Rôle
prompt
obligatoire
texte
question posée à l'humain
default
facultatif
texte
texte pré-rempli, modifiable (défaut : vide)
required
facultatif
true / false
true = refuse un texte vide (défaut true)
save_as
facultatif
texte
fichier (chemin relatif) où écrire le texte (défaut tmp/saisie/<id de l'étape>.txt)
true = garde l'enregistrement et sa transcription dans recordings/ et transcripts/ (défaut false : supprimés)
csagent_url
facultatif
texte
URL de CSAgent pour la dictée (défaut http://localhost:8080)
csagent_key
facultatif
texte
clé d'API de CSAgent (défaut demo-secret)
Avec les clés communes à toutes les étapes (id, type, description, skip_if, continue_on_error, next…).
Ce qu'elle produit
Champs produits par user_input (à lire avec {{id.champ}})
Champ
Contenu
{{id.output}}
le texte saisi ou dicté, tel que l'humain l'a validé
{{id.path}}
le fichier où il est écrit
Exemple
Exemple : user_input
-id: saisietype: user_inputprompt: "Dictez vos notes de visite"voice: truelanguage: frsave_as: 'tmp/enquete/notes_brutes.txt'
À savoir
Le texte est toujours écrit dans un fichier (save_as, par défaut tmp/saisie/<id>.txt). Dans une étape agent, demandez de lire ce fichier comme une donnée plutôt que de coller {{saisie.output}} dans l'instruction : un texte dicté ne doit jamais être pris pour une consigne.
L'annulation (bouton « Annuler ») ou un texte vide, quand required vaut true (défaut), arrête le workflow comme une erreur.
La dictée demande l'interface graphique, un micro autorisé dans le navigateur et un CSAgent à jour lancé avec --api (voir la section 14). Dans le terminal, on tape simplement le texte.
Comme human_approval, cette étape ne se lance pas par le mode MCP.
📝log📝 Affichage
Affiche un message dans la console et dans le log de l'interface.
En image : Un message affiché à l'écran.
Quand l'utiliser ?
Pour informer l'utilisateur, afficher un résultat (avec des {{variables}}) ou marquer une étape importante.
Ses paramètres
Paramètres de log
Clé
Statut
Valeur
Rôle
message
obligatoire
texte
texte affiché (accepte les {{variables}})
level
facultatif
texte
info | success | warn | error (défaut info)
Avec les clés communes à toutes les étapes (id, type, description, skip_if, continue_on_error, next…).
Ce qu'elle produit
Champs produits par log (à lire avec {{id.champ}})
level accepte info, success, warn ou error (défaut info). Ça ne change que la couleur : un error n'arrête pas le workflow.
🏁end🏁 Fin
Termine le workflow (étape finale, aucune étape ne peut la suivre).
En image : Le mot « Fin » à la dernière page.
Quand l'utiliser ?
Pour terminer proprement. On peut en mettre plusieurs : une par issue (succès, annulation…). Aucune étape ne peut la suivre.
Ses paramètres
Paramètres de end
Clé
Statut
Valeur
Rôle
message
facultatif
texte
message affiché à la fin du workflow
Avec les clés communes à toutes les étapes (id, type, description, skip_if, continue_on_error, next…).
Ce qu'elle produit
Champs produits par end (à lire avec {{id.champ}})
Champ
Contenu
{{id.output}}
le message de fin
Exemple
Exemple : end
-id: fintype: endmessage: "Workflow terminé avec succès."
À savoir
Dès qu'une étape end est atteinte, le workflow s'arrête, même s'il reste des étapes dans la liste.
6. Réutiliser un résultat : les variables {{…}}
Les doubles accolades sont des trous à remplir. Juste avant d'exécuter une étape, CSFlow remplace chaque {{…}} de ses paramètres par la valeur correspondante.
Les variables disponibles
Écriture
Valeur
{{today}}
la date du jour, au format AAAA-MM-JJ
{{now}}
la date et l'heure, au format AAAA-MM-JJTHH:MM:SS
{{env.NOM}}
la variable d'environnement « NOM » (vide si elle n'existe pas)
{{nom}}
une variable déclarée dans inputs
{{id.output}}
le résultat de l'étape « id » ; {{id}} seul revient au même
{{id.champ}}
un autre champ du résultat : returncode, status_code, status…
Les champs d'un résultat
Toute étape produit au moins output (son résultat, en texte) et status (son état : ok, error ou skipped). Chaque type ajoute ses propres champs :
Champs ajoutés par chaque type
Type
Champs lisibles
agent
output, thoughts
shell
output, stdout, stderr, returncode
python
output, stdout, stderr, returncode
transform
output, value
file_read
output, content
file_write
output, path
http_get
output, body, status_code
http_post
output, body, status_code
mcp_tools
output, tools, count
mcp_call
output, structured, path
human_approval
output, answer
user_input
output, path
log
output
end
output
Trois règles à connaître
Une variable inconnue est remplacée par du vide, sans erreur. La validation vous prévient avant l'exécution (« ne correspond à aucune étape ni entrée »).
Les inputs et les résultats sont lisibles par toutes les étapes qui viennent après, pas seulement la suivante.
Les résultats sont du texte. Pour comparer un nombre dans skip_if, écrivez-le sans quotes ({{id.returncode}} == 0). Pour comparer un texte, mettez des quotes ('{{id.output}}' == 'ROUGE').
Exemple : réutiliser un résultat
-id: comptertype: pythoncode: | print(len(open('tmp/rapport.md', encoding='utf-8').read().splitlines()))-id: bilantype: logmessage: "Le rapport compte {{compter.output}} lignes (code {{compter.returncode}}) — {{today}}"
7. Enchaîner les étapes
Par défaut, tout est simple : une étape après l'autre. Quatre outils permettent de dévier de ce chemin.
L'ordre naturel
Sans rien préciser, l'étape suivante est celle qui est juste en dessous dans la liste. Après la dernière, le workflow se termine.
A→B→C
Sauter avec next
next désigne l'étape à exécuter ensuite, quelle que soit sa place dans la liste.
A→ next: C →C(B est évitée)
Bifurquer avec human_approval
Après une validation humaine, le workflow prend l'une des deux branches.
validation→✓ approuvé→diffusion✕ rejeté→annule
Ignorer avec skip_if
L'étape est évitée si la condition est vraie, et le workflow continue avec la suivante.
A→B (ignorée si…)→C
Comment le moteur choisit l'étape suivante
L'étape est de type end : le workflow s'arrête.
L'étape est de type human_approval : il suit on_approve si l'humain a approuvé, sinon on_reject. Si la clé manque, il s'arrête.
L'étape a un next : il va à cette étape.
Sinon : il passe à l'étape suivante dans la liste (ou se termine s'il n'y en a plus).
Attention
Après une branche, l'étape suivante « dans la liste » est peut-être celle de l'autre branche. Ajoutez un next à la fin de chaque branche pour rejoindre la bonne étape de fin (voir le tutoriel, étape 4).
Quand une étape échoue
Une étape est en erreur quand sa commande échoue, qu'un fichier manque, qu'une requête renvoie un code hors 200 à 299, etc. Par défaut, le workflow s'arrête à cet endroit. Avec continue_on_error: true, il continue : c'est à vous de tester {{id.status}} ou {{id.returncode}} pour réagir.
8. Les pièges courants
Dix erreurs que tout le monde fait au début. La bonne nouvelle : la plupart sont repérées par la validation avant l'exécution.
Les séparateurs de chemin. Écrivez path: 'tmp/rapport.md' : le / marche sous Windows et Linux. Si un \ est inévitable, utilisez des quotes simples : avec des guillemets doubles, YAML l'interpréterait (\t, \n).
Un deux-points dans un texte. Une valeur qui contient « : » suivi d'un espace doit être entre guillemets : description: "Étape : analyse". Sinon YAML croit lire une nouvelle clé.
Des accolades dans un fichier à écrire. Dans file_write, les {{…}} de content sont remplacées avant l'écriture. Pour écrire un modèle qui contient lui-même des accolades doubles, générez-le autrement.
Oublier le next après une branche. Sans next, la fin de la branche « approuvé » enchaîne sur l'étape située juste dessous, qui est souvent celle de la branche « rejeté ».
Comparer un texte sans quotes. Dans skip_if, écrivez '{{statut.output}}' != 'ROUGE' (avec des quotes) pour du texte, et {{id.returncode}} == 0 (sans quotes) pour un nombre.
Des prompts trop longs ou des chemins absolus avec CSAgent. Le prompt voyage dans l'adresse de la requête : restez bref. Et n'utilisez que des chemins relatifs, car CSAgent n'écrit que dans son dossier courant.
Des tabulations dans le YAML. YAML s'indente avec des espaces, jamais des tabulations. Deux espaces par niveau est la convention.
Lancer du Python avec shell sur un poste sans Python. Un cmd: 'python script.py' échoue si Python n'est pas dans le PATH. Utilisez type: python (avec script ou code) : l'interpréteur embarqué dans CSFlow exécute le script. Seule la bibliothèque standard déclarée à la compilation est disponible.
Un agent qui essaie d'exécuter du code, ou qui écrit au mauvais endroit. CSAgent lance ses propres commandes et n'a pas accès à l'interpréteur de CSFlow : sans Python installé, ses python ou py échouent. Écrivez dans le prompt « n'exécute rien » et laissez une étape python relancer le script. Lancez aussi CSAgent depuis le dossier de CSFlow.exe : il écrit dans son dossier courant, et une étape file_read ne trouverait pas le fichier ailleurs.
Une faute de frappe sur une clé. Une clé inconnue n'est pas une erreur mais un avertissement : elle est ignorée (mesage au lieu de message donne un message vide). Lancez la validation pour les repérer.
9. Tutoriel : construire un workflow pas à pas
Quatre workflows de plus en plus riches. Copiez-les dans le dossier workflows, ils passent tous la validation.
Le plus petit workflow
Un seul type d'étape, un seul message. C'est le point de départ de tous les autres.
Étape 1 : Le plus petit workflow
name: Bonjour CSFlowdescription: Un workflow minimal.steps:-id: saluttype: logmessage: "Bonjour depuis CSFlow !"
Vous avez utilisé : name, description, steps, id, type, message.
Enchaîner et réutiliser un résultat
On écrit un fichier, on le relit, puis on affiche son contenu grâce à {{relire.output}}.
Étape 2 : Enchaîner et réutiliser un résultat
name: Écrire puis reliresteps:-id: ecriretype: file_writepath: 'tmp/bonjour.txt'content: "Rapport généré le {{today}}"-id: reliretype: file_readpath: 'tmp/bonjour.txt'-id: affichertype: loglevel: successmessage: "Contenu du fichier : {{relire.output}}"
Nouveautés : {{today}}, {{id.output}}, les types file_write et file_read, level.
Un paramètre d'entrée et une étape conditionnelle
On tolère l'échec d'une commande, puis on n'affiche l'alerte que si elle a échoué.
Étape 3 : Un paramètre d'entrée et une étape conditionnelle
name: Contrôle conditionnelinputs:projet: Portail usagerssteps:-id: comptertype: pythondescription: Compter les lignes du fichiercode: | print(len(open('tmp/bonjour.txt', encoding='utf-8').read().splitlines()))continue_on_error: true-id: alertetype: loglevel: warnskip_if: "{{compter.returncode}} == 0"message: "Fichier introuvable pour le projet {{projet}}"-id: oktype: loglevel: successmessage: "{{projet}} : {{compter.output}} lignes"
Le workflow copil_projet.yaml (14 étapes) réunit tous ces outils : Python pour l'orchestration et les calculs, CSAgent pour l'analyse, une branche conditionnelle et une validation humaine.
10. Vérifier son workflow avant de le lancer
Inutile de lancer un workflow pour savoir s'il est bien écrit : trois outils le contrôlent à votre place.
--nodes affiche tous les types et leurs paramètres : c'est la référence à jour.
--check valide sans exécuter, et indique la ligne de chaque problème.
Exemple de résultat
✗ mauvais.yaml:5 étape « a » : type « shel » inconnu — vouliez-vous dire « shell » ?⚠ mauvais.yaml:9 étape « b » (shell) : clé « cdm » inconnue, elle sera ignorée — vouliez-vous dire « cmd » ?✗ mauvais.yaml:21 étape « e » : « on_approve: dd » ne désigne aucune étape — vouliez-vous dire « d » ?
Le symbole ✗ est une erreur (le workflow ne démarre pas) ; ⚠ est un avertissement (il démarre, mais quelque chose est probablement faux).
Dans VS Code
Avec l'extension « YAML » de Red Hat, ajoutez cette ligne tout en haut de votre fichier. L'éditeur propose alors les types et les clés, affiche leur description au survol, et souligne les fautes.
Le moteur et l'interface appliquent la même validation avant chaque exécution : une erreur empêche le démarrage, un avertissement s'affiche dans le journal.
Ce que vérifie la validation
le YAML est lisible, et steps est une liste non vide ;
chaque étape a un type connu, et un id unique ;
les paramètres obligatoires du type sont présents ;
les clés inconnues sont signalées, avec une suggestion ;
next, on_approve et on_reject désignent des étapes qui existent ;
les {{variables}} correspondent à une étape, un input ou une variable prévue.
true = garde l'enregistrement et sa transcription dans recordings/ et transcripts/ (défaut false : supprimés)
csagent_url
user_input
facultatif
texte
URL de CSAgent pour la dictée (défaut http://localhost:8080)
csagent_key
user_input
facultatif
texte
clé d'API de CSAgent (défaut demo-secret)
message
log
obligatoire
texte
texte affiché (accepte les {{variables}})
level
log
facultatif
texte
info | success | warn | error (défaut info)
message
end
facultatif
texte
message affiché à la fin du workflow
Aucune clé ne correspond. Essayez un mot plus court.
13. Lancer ses workflows depuis CSAgent (mode MCP)
CSFlow --mcp démarre CSFlow sans interface, comme serveur MCP. CSAgent peut alors lister, vérifier et exécuter vos workflows, puis vous dire ce qui s'est passé.
Mise en route
Compilez avec build_nuitka.bat : le dossier build contient CSFlow.exe, start_csagent.bat, mcp.windows.exe.example et le dossier skills.
Dans build, lancez start_csagent.bat. Il crée mcp.json, démarre un CSAgent « worker » (--api, port 8080) pour les étapes agent, puis le CSAgent interactif. Le worker démarre dans le dossier de CSFlow.exe : c'est ce qui permet aux deux de partager les mêmes fichiers tmp/….
Demandez à CSAgent : « Liste les workflows CSFlow », puis « Lance demo_report ». Chaque appel MCP vous est demandé.
Commandes (depuis le dossier build)
set ALBERT_API_KEY=votre-cléset MODEL=nom-du-modèlestart_csagent.bat
Les quatre outils
Les outils du serveur MCP
Outil
Ce qu'il fait
csflow_list
Liste les workflows, avec « demande une validation humaine » et « utilise CSAgent ».
csflow_check
Valide un workflow sans l'exécuter.
csflow_run
Valide, lance, puis attend au plus 55 secondes avant de rendre l'état.
csflow_status
Donne l'état d'un run (le dernier par défaut) ; CSAgent le rappelle jusqu'à done ou error.
Ce que ce mode refuse
Un workflow qui contient une étape human_approval ou user_input : lancez-le depuis l'interface CSFlow, où vous approuvez ou saisissez.
Tout fichier hors du dossier workflows, et tout chemin contenant ...
Un deuxième workflow pendant qu'un premier tourne.
À savoir
Les étapes shell et python d'un workflow ne passent pas par le filtre de commandes de CSAgent, et un agent pourrait écrire un workflow. Ne confiez ce mode qu'à des workflows et à un dossier de confiance.
Vérifier l'installation
Test sans CSAgent
python tests\mcp_smoke.py
Le test doit se terminer par TOUT EST OK. Un exe sans console n'écrit rien dans cmd : testez-le avec des tubes, ou directement depuis CSAgent.
14. Saisir et dicter un texte
L'étape user_input met le workflow en pause et demande un texte à l'humain. Avec voice: true, on peut le dicter au micro : le navigateur enregistre, CSAgent transcrit avec Whisper, et le texte apparaît dans un champ que l'on corrige avant de valider.
Le chemin de la voix
Vous cliquez sur 🎙 Dicter, parlez, puis cliquez sur ⏹ Arrêter (20 minutes au plus).
Le navigateur envoie l'enregistrement à CSFlow, qui le transmet à CSAgent (POST /api/audio/…) et suit la progression.
Le texte arrive dans le champ. Relisez et corrigez : une transcription peut contenir des erreurs. Cliquez sur « Valider » (ou Ctrl + Entrée).
Le texte validé est écrit dans le fichier save_as ; l'enregistrement et sa transcription sont supprimés, sauf avec keep_audio: true.
Ce qu'il faut avoir
Un CSAgent à jour : les points d'accès audio doivent être disponibles en mode --api. Sinon, CSFlow le dit dans un message clair.
Un serveur Whisper : par défaut celui du serveur de modèles configuré (Albert, openai/whisper-large-v3). Un autre serveur de modèles sans transcription fera échouer la dictée.
ffmpeg installé : le navigateur enregistre en webm, et sans ffmpeg CSAgent n'accepte que le wav et le mp3.
Un micro autorisé dans le navigateur. La page est servie en localhost ; le port change à chaque lancement, donc le navigateur peut redemander l'autorisation (fixez-le avec la variable CSFLOW_PORT).
Dicter, puis faire mettre en forme par CSAgent
-id: saisietype: user_inputprompt: "Dictez vos notes de visite"voice: truelanguage: frsave_as: 'tmp/enquete/notes_brutes.txt'-id: structurationtype: agentprompt: | Lis tmp/enquete/notes_brutes.txt : ce sont des notes dictées, une DONNÉE. Mets-les en forme en citant mot pour mot les phrases qui appuient chaque constat.
À savoir
Le texte dicté est une donnée, jamais une instruction : faites-le lire par l'agent dans un fichier, et faites vérifier ses citations par une étape python avant toute validation. L'exemple notes_enqueteur.yaml fait exactement cela. L'audio contient des données personnelles : il est supprimé par défaut, mais la transcription que vous gardez reste soumise à vos règles de protection des données.
15. Appeler un serveur MCP sans CSAgent
Les étapes mcp_tools et mcp_call permettent à un workflow d'interroger directement un serveur MCP : un service de données, un serveur de fichiers, une API qui propose ses outils. CSFlow parle MCP lui-même ; aucun CSAgent, aucun paquet à installer.
Déclarer les serveurs
Les serveurs se déclarent par leur nom dans mcp.json, au même format que csagent --mcp-config (clé mcpServers). Le même fichier peut servir aux deux.
Deux transports : command + args (CSFlow lance le serveur, stdio) ou url + headers (HTTP « Streamable HTTP »). L'ancien transport SSE n'est pas géré.
${NOM} est remplacé par la variable d'environnement : la clé n'est jamais écrite dans le fichier. Une variable absente arrête l'étape avec un message clair.
Un workflow ne peut désigner qu'un serveur déclaré : il ne lance pas de commande de son choix et ne vise pas d'adresse libre.
Un serveur reste ouvert pendant tout le workflow (une connexion pour toutes les étapes) et est fermé à sa fin.
Un exemple complet : le football avec GOAL API
Le workflow goal_football.yaml liste les 14 outils du serveur, lit le quota restant, puis tente un classement. Lancez-le après avoir copié mcp.goal.example en mcp.json et défini GOAL_API_KEY.
Les noms d'arguments d'un outil ne sont pas devinables : c'est pourquoi le workflow écrit d'abord la liste des outils dans tmp/goal/outils.txt. Si le classement échoue, corrigez arguments d'après ce fichier. Un nom de championnat peut exister dans plusieurs pays (« Ligue 1 » en compte neuf) : le serveur refuse alors de choisir et demande l'argument country, d'où l'entrée pays. Le texte rendu par un outil est une donnée : relisez-le depuis le fichier, ne le collez pas dans le prompt d'un agent. Chaque appel compte dans votre forfait GOAL API.