La Roxabi Factory

Un moteur d'agents étendu d'une couche jobs — les choix qui le façonnent, et l'ordre dans lequel on les construit.

Version 1.1 · Mis à jour

01

Un moteur, étendu

La Factory n'est pas un nouveau système. C'est le moteur d'agents qui anime déjà les bots Roxabi — un cœur hexagonal (ports & adapters), une topologie hub-and-spoke, un registre d'agents et un pool de workers distribués sur un bus de messages — étendu d'une seule couche nouvelle : les jobs. Cette couche transforme l'activité en contenu, le publie, et fait tourner la boucle autour.

La conséquence est libératrice. Le cœur qu'il reste à bâtir est plus petit que ne le suggérait le premier brain-dump : le pool de workers, le bus, les contrats typés, le scheduler — tout tourne déjà en production. La règle de cadrage en découle directement — toute nouvelle capacité est un adapter sur l'hexagone, jamais un nouveau cœur.

Le moteur existe déjà. La Factory est une couche jobs par-dessus — une extension, pas une réécriture.

02

La valeur avant le framework

Le plan naïf construit d'abord le framework : un cœur générique, puis les modules, puis la publication, puis les routines. C'est le piège classique — une machine générale plantée devant sa première unité de valeur. On l'inverse.

D'abord une tranche verticale fine, sous contrôle humain de bout en bout : un signal de ce qui a été fait → le worker génère un post → un humain approuve → ça publie. Elle réutilise le bus et le pool de workers ; le harness est minimal ; pas encore de framework. Ensuite on mesure le reach. Alors seulement on généralise le harness et le watcher — et uniquement sur les briques que la tranche a prouvées nécessaires.

Le contrôle humain (HITL) est le défaut tant que le reach — et le risque réputationnel sur deux marques — n'est pas mesuré. Une porte, pas une arrière-pensée.

03

Un worker n'est pas un outil

La décision la plus clarifiante du design. Les mots « outil » et « worker » avaient dérivé à travers quatre espaces de design parallèles ; voici la ligne qui les résout.

Deux rôles, tenus séparés. Un provider est le service qui porte un outil — et quand c'est un processus auto-hébergé qu'on fait tourner sur le bus avec un heartbeat, c'est un satellite. Un provider expose plusieurs outils : le satellite image expose image.generate, image.list_engines, image.cancel. Un worker est l'autre bout — une instance de calcul qui consomme des outils pour exécuter un job. Un worker n'est pas un outil, ni un provider ; c'est ce qui fait le travail.

Et un worker n'improvise pas. Il fait tourner un workerEngine — un pipeline codé, une séquence déterministe — qui appelle trois sortes d'étapes : le harness (un tour agentique pur, où le modèle décide et où ses outils du tour s'exécutent, sans aucune logique de workflow propre), les outils, et du code interne simple. Le harness est un appelé du moteur, pas une de ses saveurs — de l'agentique là où l'on veut une décision, du code là où l'on veut une garantie.

  • Provider — le service qui porte un outil. Indépendant du transport ; un provider, plusieurs outils.
  • Satellite — un provider déployé en processus auto-hébergé sur le bus, avec un heartbeat. Tout satellite est un provider ; tout provider n'est pas un satellite.
  • Worker — une instance de calcul qui consomme des outils pour exécuter un job. Ni outil, ni provider.
  • workerEngine — le pipeline codé que fait tourner un worker ; orchestre harness, outils et code interne.
  • Harness — un tour agentique pur ; le modèle décide. Une étape que le moteur appelle, jamais le pipeline lui-même.

Pour la boucle de raisonnement du modèle, un image.generate distant et un bash intégré sont identiques — même forme, même type de résultat. La différence de transport est invisible.

Satellite Image un provider · heartbeat · une identité image.generate image.list_engines image.cancel 1 provider → N outils Registre découvert par heartbeat Harness tour agentique pur Worker fait tourner un workerEngine consomment pour le modèle :  bash (intégré)  ≡  image.generate (distant) le transport est invisible — une forme, un type de résultat
Un provider expose des outils — un satellite quand il est auto-hébergé sur le bus. Enregistré une fois, chaque outil est consommé à l'identique par le harness et les workers — un appel distant et un intégré sont indiscernables pour le modèle.
04

Cinq couches d'outils

Tous les outils ne sont pas atomiques. Le modèle compte cinq couches, d'un appel primitif unique jusqu'au sous-agent récursif — et un seul pipeline les distribue toutes.

  • L0a — Intégré. Compilé dans le moteur ; en-processus ; toujours disponible. bash, lecture/écriture de fichier, web fetch.
  • L0b — Distant. Un satellite de capacité sur le bus, découvert par heartbeat. image.generate, voice.tts.
  • L1 — Macro. Une chaîne déterministe de primitives, sans second modèle dans la boucle.
  • L2 — Skill. Un composite de couche-instruction — un document qui guide le modèle à travers une séquence métier.
  • L3 — Sous-agent. Un appel d'agent imbriqué et isolé qui remonte un résumé.

Le choix décisif est un dispatcher uniforme : une seule porte de contrôle d'accès, un seul type de résultat, le transport variant en dessous. Pas un pipeline ramifié où intégrés et distants font chacun croître leurs propres règles — la discipline d'un chemin unique est ce qui garde le moteur lisible en un après-midi.

COMPOSITION ↑ L3 — Sous-agent agent imbriqué isolé · remonte un résumé L2 — Skill composite couche-instruction · guide le modèle L1 — Macro chaîne déterministe · pas de second modèle L0b — Atomique distant satellite sur le bus · découvert par heartbeat L0a — Atomique intégré compilé en-processus · toujours disponible DISPATCH UNIFORME
Cinq couches, un dispatcher. D'une primitive intégrée à un sous-agent récursif, chaque outil franchit la même porte de contrôle d'accès et renvoie le même type de résultat — seul le transport change.
05

Des domaines par nature

Les contrats typés qui circulent sur le bus étaient listés à plat, mélangeant deux natures dans un même tiroir. On les sépare.

Un domaine est de nature outil quand sa seule raison d'être est d'exposer une capacité que le modèle invoque — voix, image, et les satellites de capacité à venir. Tout le reste est de la plomberie : le transport d'inférence du moteur lui-même, le bus de jobs, la persistance, la sécurité, l'observabilité, la livraison.

Le tranchant tient en une règle :

surface d'outil  ≠  nature d'outil

  plomberie github      expose un outil intégré   → reste plomberie
  substrat d'inférence  expose un appel generate  → reste plomberie

Un domaine de plomberie peut exposer un outil sans devenir de nature outil. Exposer un outil ne promeut pas le domaine wire. C'est cette règle qui garde la séparation honnête, au lieu de laisser tout dériver vers « outil ».

Une seconde règle trace la ligne à l'intérieur de « provider » — car tout provider ne tourne pas sur le bus :

provider  ⊋  satellite

  processus auto-hébergé sur le bus    →  satellite  (heartbeat — voix, image, notre adapter Postiz)
  une API cloud / un CLI one-shot      →  provider   (pas de heartbeat — X, GitHub, un outil bash)

Un provider n'est un satellite que lorsqu'il est quelque chose qu'on fait tourner sur le bus et qui émet un heartbeat ; une API cloud qu'on ne fait qu'appeler, ou un outil en ligne de commande one-shot, est un provider sans l'empreinte d'un satellite. Et un piège à éviter : un backing service auto-hébergé — une application entière comme notre fork Postiz (web, base de données, Redis) — est de l'infrastructure, comme Postgres. Un conteneur qui tourne n'est pas un heartbeat ; le heartbeat vient de notre adapter placé devant. Backing service, provider, outil : trois couches, jamais confondues.

Le gain, c'est un plan adressable. Les sujets de nature outil portent un marqueur tool.…tool.voice.tts… — pour que le côté consommateur s'abonne au plan d'outils entier d'un coup, et découvre ce qui est disponible via un registre unique.

L'isolation est le but. Dès que « les outils » forment un plan, le harness et les workers les adressent et les découvrent comme un tout.

06

La roadmap

Où cela va, dans l'ordre — le substrat d'abord, la valeur ensuite, le framework en dernier.

  • Substrat — en production : le bus, les contrats typés, le pool de workers, le scheduler.
  • Tranche fine — un signal → un post → approbation → publication ; mesurer le reach. La clé de voûte.
  • Généraliser — le harness et le job-watcher, sur ce que la tranche a prouvé nécessaire.
  • Outils — le registre partagé, le SDK d'outils, les satellites migrés sur le modèle à cinq couches.
  • Harness & workers — le harness agentique pur et une flotte de workers faisant tourner des workerEngines, consommant tous deux le plan d'outils.
Substrat en production Slice prochaine · clé de voûte Généraliser harness · watcher Outils registre · SDK Harness + Workers Architecture du système d'outils : conçue & verrouillée. L'implémentation est séquencée après la migration des sujets du bus en cours — concevoir maintenant, construire proprement ensuite.
Le substrat en production ; la tranche fine est la clé de voûte qui conditionne tout ce qui suit. L'architecture des outils est arrêtée — sa construction est séquencée derrière une migration en cours pour que deux réorganisations n'entrent jamais en collision.

Le design est arrêté ; la construction est séquencée, pas précipitée. Des primitives, pas un framework.