Case study · Duo · 2025 — 2026
CRAI — l'IDE conversationnel du hardware.
« Claude Code pour le hardware. » CRAI est un IDE desktop conversationnel pour tout ce qui est physique et embarqué : robotique, drones, IoT, firmware, CNC, PCB, ROS2, simulation, CAD. Un agent IA pilote un vrai terminal Linux isolé dans un conteneur Docker par projet — on le regarde générer, tester et itérer en temps réel.
Projet en binôme, de la première ligne au packaging. Mon rôle : fullstack & agent IA — architecture, boucle agent, backend, frontend 3D, pipeline CI, 918 tests automatisés.
Le problème résolu
Construire un objet physique — un drone, une station météo, un bras robotisé — demande de jongler entre cinq mondes outillés séparément : la CAO (Fusion, SolidWorks), l'électronique (KiCad), le firmware (PlatformIO, STM32Cube), la simulation (Gazebo) et le sourcing de composants. Chaque outil a sa courbe d'apprentissage, ses formats, ses exports. Le coût d'entrée est énorme, et l'itération est lente.
CRAI ramène tout ça dans une seule conversation :
- On décrit l'objet — « frame 5 pouces allégée, cible 120 g, firmware DShot600 » — et l'agent génère la géométrie, la valide en FEA, écrit le firmware et le compile.
- Pas de pipeline figé, pas de whitelist — l'agent a un vrai terminal Linux par projet, isolé par Docker. Il installe ce dont il a besoin, comme un ingénieur.
- Tout est inspectable — chaque appel d'outil est affiché avec sa durée, son coût, et le résultat ; le viewer 3D et le graphe du robot se mettent à jour en direct.
Architecture
Trois couches, trois responsabilités :
- Desktop Tauri 2 + React 18 — le shell natif (Rust) embarque une UI React : chat streaming, viewer 3D (react-three-fiber), éditeur de graphe (xyflow), Monaco, terminal xterm. État partagé entre TanStack Query (données serveur) et Zustand (état UI).
- Backend FastAPI + boucle agent — orchestre les tours de l'agent (Claude Opus 4.7, sous-agents Haiku), streame chaque événement en SSE (texte, appels d'outils, diffs, coût), persiste graphe, fichiers, checkpoints et mémoire cross-session (Qdrant).
- Un conteneur Docker par projet — le sandbox où tout s'exécute : génération de géométrie (OCCT), FEA, compilation firmware (ESP32, STM32, Arduino), simulation physique, ROS2. L'isolation rend l'agent libre et inoffensif.
L'agent et ses outils primitifs
Le choix de design central : peu d'outils, mais primitifs. Plutôt qu'une API par fonctionnalité (« generate_frame », « compile_firmware »…), l'agent reçoit 14 outils bas niveau — bash, lecture/écriture de fichiers, manipulation du graphe, rendu 3D… Les capacités émergent de leur composition, comme pour un humain devant un terminal.
- Boucle itérative bornée — l'agent génère, teste, lit l'erreur, corrige ; le plafond d'itérations et le coût cumulé sont affichés en permanence dans la barre d'état.
- Chaque action est une carte dans le chat — commande, durée, sortie, statut. Rien n'est caché : la confiance vient de la transparence.
- Mémoire cross-session — les décisions et préférences (visserie choisie, imprimante calibrée) survivent d'un projet à l'autre via Qdrant.
Git pour le hardware
Un robot n'est pas un dossier de fichiers : c'est un graphe — des pièces mécaniques, des composants électroniques, du firmware, reliés par des arêtes typées (mounted_on, powers, controls, simulates…). CRAI versionne ce graphe comme git versionne du code :
- Diff physique — chaque tour d'agent produit un diff du graphe (pièces ajoutées, masses modifiées, connexions déplacées) affiché comme un diff de code.
- Checkpoints restaurables — chaque message utilisateur capture graphe + arborescence ; un clic restaure l'état complet du projet à ce point.
- Validation continue — un validateur vérifie la cohérence du graphe (orphelins, alimentations manquantes, masses aberrantes) et badge chaque nœud.
Qualité — 918 tests
Un agent autonome qui exécute du code arbitraire exige une base testée sérieusement :
- 918 tests automatisés — 345 backend (86 % de couverture), 573 frontend (93 %).
- E2E Playwright — scénarios live (agent réel + Docker) et golden path mocké qui tourne en CI sans clé API, plus une suite de régression visuelle par snapshots.
- Tests d'agent déterministes — un harnais « devsim » rejoue des streams Anthropic enregistrés (cassettes) : la logique de l'agent se teste offline, gratuitement, à chaque commit.
- Deux tiers de feedback — pre-commit rapide (oxlint + tsgo sur les fichiers stagés), pre-push complet (ESLint, tsc, mypy) via lefthook.
Défis rencontrés
- Streaming d'un agent long-running — un tour peut durer plusieurs minutes et toucher chat, viewer, graphe, fichiers, coût. Solution : un canal SSE unique avec des événements typés, dispatchés vers les stores ; l'UI est une projection de l'état du backend, reconstructible après un reload (le transcript persisté rejoue le tour tel qu'il a streamé).
- Docker comme sandbox produit — démarrage à la demande, image de base outillée (OCCT, toolchains, simulateurs), quotas CPU/RAM par projet, et surtout : les échecs d'outils sont enregistrés fidèlement plutôt que masqués.
- La géométrie qui ment — une pièce générée peut être plausible et fausse. La FEA et la validation du graphe servent d'oracle physique : l'agent doit prouver que la pièce tient, pas juste l'affirmer.
- Tester l'IA sans l'IA — impossible de payer des tokens à chaque CI. Les cassettes LLM pinnent les décisions de l'agent pendant que les outils s'exécutent pour de vrai — le meilleur des deux mondes.
Apprentissages
- Les primitives battent les features. Chaque fois que j'ai été tenté d'ajouter un outil spécialisé, la bonne réponse était de rendre les primitives plus fiables. L'agent compose mieux que je ne prévois.
- La transparence est une feature de sécurité. Montrer chaque commande, chaque durée, chaque coût transforme la méfiance envers l'agent en supervision. C'est ce qui rend l'autonomie acceptable.
- L'infrastructure de test est le produit. Sur un projet à deux avec un agent non déterministe, les 918 tests et les cassettes ne sont pas du confort : c'est ce qui permet de refactorer la boucle agent un an après sans tout casser.