DisPatch : Une application de chat auto-hébergée pour les agents IA locaux
- Catégorie
- IA et LLM locaux
- Publié
- 11 juillet 2026
- Mis à jour
- 9 octobre 2026
- Par
- Jacob Lloyd — rédigé avec l'aide de l'IA, une fois le projet terminé
- Temps de lecture
- 20 min de lecture
En clair : DisPatch est une application de messagerie qui s’exécute sur votre propre ordinateur et fonctionne depuis n’importe quel téléphone ou ordinateur portable de la maison. Vous l’utilisez pour discuter avec des assistants IA qui tournent également sur cet ordinateur, ainsi que pour y déposer des fichiers afin que les assistants puissent les traiter. Un code PIN permet de verrouiller ces assistants puissants ; ainsi, sur un appareil familial partagé, seules des fonctionnalités sécurisées restent accessibles.
DisPatch est l’application que j’ai créée pour ne plus avoir à faire tourner une installation de 30 conteneurs d’Rocket.Chat uniquement pour communiquer avec mes propres agents IA. Il s’agit d’un seul processus Python et d’un fichier SQLite. Tous les appareils de la maison peuvent y accéder ; les agents répondent dans des fils de discussion, tout comme le feraient des humains. Tout ce que je dépose depuis mon téléphone se retrouve sur la machine hébergeant les agents. La version 2.0.0 est sortie le 09/10/2026 : le téléchargement correspond à un fichier zip de 3 Mo dont la suite de tests exécute 1 915 tests avec succès. Cette page explique ce que fait DisPatch, comment les réponses parviennent sur votre téléphone en une seule fois, et comment le verrouillage par code PIN empêche une tablette familiale d’accéder aux agents capables de modifier des éléments réels.
Résumé
- Qu’est-ce que c’est ? Un chat web auto-hébergé destiné aux agents IA locaux (un passerelle OpenClaw, ou une API de modèle que vous configurez), ainsi qu’une fonction de dépôt de fichiers par glisser-déposer ; utilisable depuis tout appareil pouvant accéder à l’hôte.
- Combien ça coûte ? 0 $. Pas de licence SaaS, pas d’inscription nécessaire.
- Quels prérequis ? Un système Linux avec Python 3.12+ et
uv, ou Docker. OpenClaw n’est requis que si vous souhaitez utiliser des agents capables d’utiliser des outils. - Quels avantages ? Des fils de discussion par bot, un affichage en temps réel des réponses avec bouton d’arrêt, possibilité de régénérer ou modifier les réponses, dépôt de fichiers, intégration d’outils et d’applications, dix thèmes disponibles, un Mode Sécurisé imposé par le serveur et protégé par un code PIN, ainsi qu’une API push pour les tâches planifiées.
- Le téléchargement : la version 2.0.0, identique à l’état du code marqué
v2.0.0dans le dépôt public. Licence MIT.
À quoi sert-il ?
Les captures d’écran proviennent d’une copie isolée contenant des données fictives. Les quatre premières proviennent de la version 2.0 ; les images du Mode Sécurisé et du Serveur de fichiers proviennent de la version de juillet, et elles fonctionnent de la même manière dans la version 2.0.





- Threads spécifiques à chaque bot sur tous les appareils. Ouvrez une conversation sur votre téléphone : le même thread avec le même historique s’affiche. Les threads peuvent être épinglés, archivés, renommés ou recherchés.
- Réponses en markdown en temps réel avec mise en évidence syntaxique du code et boutons de copie, prévisualisations d’images et vidéos via un lightbox, ainsi qu’une PWA installable.
- Un panneau de suivi en temps réel et un bouton Arrêter. Une ligne d’état indique l’action en cours (chargement du modèle, écriture, utilisation d’un outil). Cliquez sur les points de frappe pour observer le raisonnement du bot et ses appels d’outils ; appuyez sur Arrêter pour interrompre le processus.
- Les commandes classiques des applications de chat. La fonction Regénérer conserve les réponses précédentes ; vous pouvez modifier un message et le relancer, citer une réponse, voter pour ou contre, ou supprimer un message du contexte. Chaque thread permet de choisir le modèle et le niveau de raisonnement utilisés ; un indicateur montre le taux d’utilisation du contexte.
- Brouillons et boîte de sortie hors ligne. Un brouillon non envoyé reste lié à son thread ; un message envoyé sans connexion est mis en attente et transmis dès que la connexion revient.
- Outils et applications. Un bouton Outils permet d’ouvrir vos propres projets au sein de l’application : un dossier statique, une page web ou un paquet d’applications fiable doté de son propre backend et bot. Le Tableau des tâches est la première application disponible.
- Deux façons de faire parler un IA. Vous pouvez associer directement un bot à une API de modèle (LM Studio, Ollama, OpenAI, Anthropic ou tout autre service compatible OpenAI) via les paramètres ; vous pouvez aussi connecter un passerelle OpenClaw pour des agents utilisant des outils et agissant sur la machine.
- Une API de push.
POST /api/injectpermet à un cron job ou à un autre agent d’ajouter un message dans un thread. C’est ainsi qu’un bulletin matinal parvient sur mon téléphone sans que j’aie rien demandé. - Verrouillage en deux niveaux. Un code PIN sépare les agents à pleine capacité du sous-ensemble « sécurisé ». Plus de détails ci-dessous.
- Tableau de bord d’hébergement. État de santé, espace de stockage, intégrité de la base de données et statut des sauvegardes ; une liste de vérification indique les paramètres mal configurés.
- Huit langues d’interface, dont l’arabe écrit de droite à gauche, et dix thèmes.
- Un visionneur local. Cliquez sur un chemin de fichier dans un message : le fichier s’ouvre directement dans l’application, même depuis un téléphone. Aucun fichier n’est servi tant qu’aucun dossier n’a été sélectionné ; les chemins système ou confidentiels ne sont jamais exposés.
Les agents peuvent également publier des images dans un thread. Un bot insère alors un marqueur [[pic:prompt|caption]] dans sa réponse ; un espace réservé apparaît immédiatement, puis se transforme en image une fois le rendu terminé. Mes images proviennent d’une machine équipée d’un GPU située sur le réseau. Si cette machine est hors service, l’espace réservé indique simplement ce problème au lieu de rester silencieux.
Le serveur de fichiers
C’est l’outil que j’utilise le plus. Ouvrez DisPatch sur n’importe quel appareil, déposez un fichier dessus, et il se retrouve sur le serveur, regroupé par jour, avec des miniatures pour les images et les vidéos.

L’intérêt principal réside dans l’emplacement où les fichiers sont stockés : sur la même machine que celle exécutant les agents. Une photo envoyée depuis mon téléphone peut être lue par un agent quelques secondes plus tard ; je peux ainsi la décrire, la classer ou la publier sur un site web, sans avoir besoin d’un disque cloud ni de câble.
Le code prévient les principaux modes de défaillance :
- La taille maximale autorisée pour l’upload est vérifiée avant que FastAPI ne bufferise le corps du fichier ; ainsi, un téléphone ne peut pas épuiser la mémoire de l’hôte.
- L’espace de stockage total est limité à 20 Go par défaut (
DISPATCH_FILES_TOTAL_MAX; mettre cette valeur à 0 désactive la limite). - Chaque fichier uploadé est d’abord enregistré dans un fichier temporaire, puis synchronisé et renommé pour prendre sa place définitive ; en cas de coupure de connexion, aucun fichier incomplet n’est laissé en état.
- Un appareil verrouillé ne peut effectuer qu’un upload unidirectionnel. Il peut envoyer un fichier, mais ne peut ni parcourir ni télécharger les fichiers déjà présents sur le serveur.
Pourquoi l’ai-je développé au lieu d’utiliser une interface existante ?
Rocket.Chat fonctionnait, mais disposer d’une base de données et d’une multitude de conteneurs représentait trop d’infrastructure pour simplement « envoyer du texte, recevoir du texte en retour, et le synchroniser partout ».
Open WebUI et LibreChat sont les solutions habituelles pour un « chat IA auto-hébergé » ; elles savent bien interagir avec les modèles. Mes besoins étaient cependant différents. Je voulais des agents participant aux conversations partagées par toute la maison, un mécanisme de verrouillage imposé par le serveur pour les appareils utilisés par les enfants, un point de terminaison HTTP vers lequel les scripts peuvent envoyer des données, ainsi que des fichiers accessibles aux agents. C’est cette combinaison que propose DisPatch. Si vous souhaitez simplement une jolie interface pour interagir avec un modèle, commencez plutôt par l’un de ces outils.
De plus, il n’y a aucune étape de compilation. L’interface utilise des modules JavaScript standards ainsi que du CSS/HTML pur, sans aucun outil d’agrégation ni npm run build. Mon critère principal lors du développement était que « l’interface soit facilement modifiable par un agent IA plus tard » : il suffit de modifier un fichier et de rafraîchir la page. Je referais le même choix aujourd’hui.
Contenu du téléchargement
L’archive ZIP s’appelle dispatch-2026-10.zip ; il s’agit de la version DisPatch 2.0.0, identique octet par octet à l’étiquette v2.0.0 du dépôt public. Voici les mesures effectuées pour cette version :
| Élément | Dans l’archive ZIP |
|---|---|
| Taille du téléchargement | 2 992 647 octets (2,9 Mo) ; 319 fichiers, soit 7,9 Mo une fois décompressés |
| SHA-256 | e9824d3c13bb3acd2d2eebcf2b162b14ae26eb86f56ca0e4ac8aa20f686a2398 |
| Backend | Python 3.12+, FastAPI + uvicorn, un fichier SQLite, géré via uv. 36 501 lignes dans backend/app/ (main.py contient 12 331 lignes), plus 5 497 lignes pour l’application Job Board intégrée |
| Tests | 30 726 lignes de tests Python ; pytest indique 1 915 tests réussis, et 473 tests front-end s’exécutent via node --test |
| Frontend | JavaScript pur, sans compilation : environ 21 000 lignes en dehors des bibliothèques et tests intégrés, plus environ 9 300 lignes de CSS et HTML |
| Bibliothèques intégrées | marked, highlight.js, DOMPurify. Aucun appel à un CDN |
| Données | Hors code source, par défaut dans ~/.local/share/local-chat/ (ancien nom du projet) : la base de données, config.yaml, security.yaml, les médias, les fichiers et les sauvegardes rotatives de la base de données |
| Licence | MIT |
Qu’a-t-il changé depuis l’archive 1.0.0 d’août :
- Les réponses suivent désormais un chemin rapide et ne se perdent plus. Les messages sont désormais envoyés au gateway de l’agent via le WebSocket déjà ouvert, plutôt que de lancer un nouveau processus
openclawpour chaque message. Cela a permis de réduire d’environ une seconde le temps de traitement de chaque réponse (de 2,26 s à 1,12 s, selon les mesures). Le texte est transmis au fur et à mesure que le modèle le génère. Chaque requête acceptée par le gateway est suivie jusqu’à son achèvement ; ainsi, une réponse parvient tout de même après une déconnexion ou un redémarrage du serveur. - Licence. La version 1.0.0 était sous licence AGPL-3.0. Le projet a été relicencié sous MIT le 30 août 2026 ; la version 2.0.0 est donc sous licence MIT. Les anciennes archives de juillet et août restent disponibles à leurs adresses respectives, chacune portant son propre fichier
LICENSE. - Le terminal de codage a disparu. La version 1.0.0 proposait un terminal intégré dans le navigateur (un PTY côté serveur transmis à xterm.js). Je l’utilisais pour un agent de codage que j’ai depuis retiré ; la version 2.0 enlève donc ce composant ainsi que sa bibliothèque associée. Le panneau DeepSeek Harness, activable lorsque
dshest installé, remplit désormais cette fonction et permet de lancer, surveiller et arrêter des sessions en temps réel. - Nouveautés : contrôles de conversation, brouillons et boîte d’envoi, outils et applications, tableaux de checklist, visionneur local, marqueurs d’images, dix thèmes au lieu du simple commutateur clair/sombre, ainsi que des lignes de messages plus discrètes. La liste complète figure dans le fichier
CHANGELOG.mddu dépôt.
Configuration
Ceci est un résumé du README.md et des fichiers dans docs/ contenus dans le fichier zip. Il s’agit d’un projet uv classique :
unzip dispatch-2026-10.zip
cd DisPatch-2.0.0/backend
uv sync --frozen
uv run pytest -q # 1,915 passed on my machine
uv run uvicorn app.main:app --host 0.0.0.0 --port 8765
Ou alors, omettez Python : exécutez simplement cp .env.example .env && docker compose up -d depuis le répertoire racine du fichier décompressé. Le dossier deploy/systemd/ contient les fichiers unit pour la version toujours active, et docs/deploy-bare-metal.md explique l’étape que tout le monde oublie : loginctl enable-linger. Sans cela, votre service utilisateur s’arrête dès que vous fermez la session SSH.
- Définissez d’abord un code PIN (icône en forme d’engrenage, puis section Sécurité). Les deux commandes ci-dessus écoutent sur
0.0.0.0; donc tant qu’aucun code PIN n’est défini, toute personne sur votre réseau dispose d’un accès complet. Utilisez--host 127.0.0.1(ouBIND_ADDR=127.0.0.1pour Docker) pendant vos tests, et ne redirigez surtout pas le port vers Internet. - Modifiez le fichier
config.yamldans le répertoire de données afin que les identifiantsiddu bot correspondent à ceux de vos agents OpenClaw. Le fichier est rechargé automatiquement lorsqu’il est modifié. - Les paramètres proviennent des variables d’environnement préfixées par
DISPATCH_; toutes sont listées dans.env.example:HOST,PORT,DATA_DIR,AGENT_TIMEOUT(900 secondes),MAX_CONCURRENCY(3),GATEWAY_WS. DISPATCH_MAX_CONCURRENCYlimite le nombre d’exécutions d’agents simultanées. La valeur par défaut, 3, protège une machine exécutant des modèles locaux. Un quatrième message attend son tour ; il n’est pas rejeté.
DisPatch ne fournit pas OpenClaw. Pour les agents, il nécessite un passerelle OpenClaw sur le même hôte. Sans elle, l’application démarre quand même et affiche un avertissement dans les logs. Les threads, l’API d’injection, le serveur de fichiers, le verrouillage par code PIN, les outils ainsi que les API de modèles restent fonctionnels. C’est ainsi que je procède aux tests du fichier zip : décompression, uv sync, choix d’un port libre, et absence de passerelle.
Comment la réponse vous parvient
La majeure partie du travail d’ingénierie a porté sur les cas de défaillance : perte de connexion en plein envoi, redémarrage du serveur alors qu’un traitement est en cours, ou réponse d’un sous-agent arrivant dix minutes plus tard. Le mode de transport est choisi via DISPATCH_GATEWAY_WS. S’il n’est pas défini, chaque message lance un processus openclaw agent qui renvoie la réponse une fois terminé. shadow se connecte et enregistre ce qu’il aurait livré sans effectivement le faire. 1 signifie que les messages transitent par le socket du gateway, et que les réponses y sont renvoyées en streaming. J’utilise 1. Le fichier zip le désactive par défaut, donc rien ne change dans la livraison des réponses tant que vous ne l’activez pas.
Avec le socket activé, chaque traitement accepté par le gateway est inscrit dans une table dédiée et finalisé via l’appel spécifique du gateway indiquant « attendre la fin de ce traitement ». Même si le flux en temps réel est interrompu, la réponse arrive dès que le traitement se termine ; de plus, les traitements en cours au moment de la panne du serveur sont récupérés lors du redémarrage. Seuls les traitements jamais acceptés par le gateway font l’objet d’une nouvelle tentative, évitant ainsi toute duplication.
Un point à noter concernant la solution de secours : le balayage des transcripts lit les fichiers de session d’OpenClaw, mais les versions récentes d’OpenClaw stockent ces données dans une base de données. Dans ce cas, DisPatch signale au démarrage que les mécanismes de secours basés sur les fichiers ne peuvent pas fonctionner, et que le socket devient alors le seul canal de livraison. C’est une raison supplémentaire d’activer le socket.
Quelle que soit la voie empruntée, chaque réponse potentielle passe par un même canal qui vérifie si elle a déjà été livrée ; ainsi, même si une réponse est détectée deux fois, elle n’apparaît qu’une seule fois. Même en cas d’erreur de CLI, le balayage s’effectue avant toute annulation, car le modèle a souvent déjà écrit sa réponse dans le transcript avant que le processus ne se termine.
Le verrouillage en deux niveaux : mode normal vs mode Sécurisé
Le côté non verrouillé n’est pas un jouet. Ces agents peuvent modifier le code, pousser des modifications sur mon site web en ligne, exécuter des outils et gérer la machine sur laquelle ils évoluent. Le côté verrouillé ne permet que les conversations générales. Il reste utile pour poser des questions ou obtenir de l’aide, mais il n’a accès à rien d’autre. Comme le téléphone familial n’est pas toujours entre les mains d’un adulte, le serveur applique ce verrouillage. Voici ce qui se passe lorsqu’une requête est émise :
La mémorisation des appareils est désactivée tant que vous ne l’activez pas dans les paramètres de sécurité, ce qui définit la durée de validité à 30 jours. Appuyer sur « Verrouiller » pour un appareil mémorisé le fait oublier ; modifier le code PIN efface tous les appareils mémorisés. Le serveur ne conserve au maximum que 10 appareils mémorisés. Si le fichier des appareils de confiance est corrompu, aucun appareil n’est considéré comme fiable, mais le code PIN continue de fonctionner.
Si vous vous retrouvez bloqué, deux moyens permettent de revenir en arrière : un fichier de codes de récupération, ou la modification directe du fichier security.yaml. Si security.yaml est endommagé, l’application reste verrouillée au lieu de permettre l’accès à tout le monde sur le réseau local. Ce choix a été fait délibérément.
Pièges à éviter
- Le champ API pour l’injection s’appelle
content.POST /api/injectattend{"bot_id": "...", "content": "..."}. Envoyer simplement dutextétait la erreur d’intégration la plus fréquente, y compris de ma part. - Ne passez pas de messages longs en tant qu’argument CLI (cela reste important même dans le mode de secours). Linux limite la taille d’un seul argument à 128 Ko (
MAX_ARG_STRLEN) ; un message trop long provoque une erreur E2BIG lors du lancement du processus. Le code écrit donc le message dans un fichier temporaire et passe--message-file. Ne “simplifiez” pas cela en renvoyant un simple argument. - Les clés de session sont en minuscules, mais les IDs de bots ne le sont pas. OpenClaw met les clés de session en minuscules, mais vos IDs peuvent contenir des majuscules (
Alpha,My_Bot). En cas de recherche sensible à la casse, le panneau de gestion et la livraison des réponses tardives cessent de fonctionner discrètement, tandis que tout le reste continue normalement. La solution consiste à effectuer d’abord une correspondance exacte, puis à utiliser la version en minuscules comme fallback. - La CLI ne renvoie que le dernier bloc de texte. Sans connexion socket, tout ce qu’un agent écrit entre deux appels d’outils n’apparaît que dans son transcript. C’est pourquoi il existe un mécanisme de nettoyage du transcript, qui continue de s’exécuter même lorsque la connexion socket est active.
- Vérifiez le champ Origin sur les WebSocket. Les middleware HTTP ne s’appliquent pas aux routes WebSocket. DisPatch effectue l’authentification en ligne et rejette toute tentative de connexion dont l’hôte
Originne correspond pas àHost, empêchant ainsi les attaques de type hijacking WebSocket croisé. Les clients non-browsers n’envoient pas de champ Origin et sont donc autorisés. - Ne servez jamais de fichiers SVG téléchargés comme des images. Un fichier SVG ouvert directement peut exécuter du script dans votre domaine, créant ainsi une faille XSS persistante. DisPatch refuse de servir les SVG en tant que médias et applique un CSP restrictif ainsi qu’un attribut
nosniffpour sécuriser le contenu. - Les mises à jour du service worker laissent les ancions onglets fonctionner avec une version obsolète de JavaScript. Cela ressemble exactement à une régression. La solution consiste à effectuer un rechargement automatique lors de l’événement
controllerchange.
Répliquer le concept
Même si vous ne lancez jamais mon fichier zip, l’architecture se compose de quatre composants remplaçables :
- Un backend de chat qui gère l’historique : un petit serveur web (ici FastAPI et un fichier SQLite en mode WAL), un WebSocket pour les mises à jour en temps réel, ainsi qu’un simple point de terminaison HTTP pour envoyer des messages. Ce composant remplace la base de données ainsi que tous les conteneurs nécessaires.
- Un gateway d’agents avec lequel le backend communique : ici OpenClaw, mais tout système capable de recevoir un identifiant de session et un message puis de renvoyer du texte convient. En tant que processus séparé, il peut planter, être mis à jour ou remplacé sans interrompre l’application de chat.
- Des serveurs de modèles derrière le gateway (LM Studio, vLLM, Ollama). Ce sont des problèmes relevant du gateway, pas de l’application de chat.
- Des services multimédias optionnels, comme un générateur d’images sur une autre machine, que les agents peuvent utiliser en tant qu’outils. Le backend se contente de stocker les résultats renvoyés.
Ces principes s’appliquent quel que soit votre ensemble de technologies :
- Activez le mode verrouillé côté serveur, jamais via CSS.
- Considérez le fait qu’« une réponse parvienne au utilisateur exactement une fois » comme un problème de livraison à prendre en compte, avec mécanismes de déduplication.
- Maintenez le frontend sans nécessité de compilation si des IA doivent le gérer.
Voir aussi : mon ensemble d’agents IA locaux sur OpenClaw · Première découverte du DeepSeek Harness · gérer mes sites web avec une boîte d’agents IA locales · configurer votre assistant LLM
Téléchargements
Gratuit pour un usage personnel. Si ça vous fait gagner un après-midi, le bouton café n'est pas loin.