❤️
FR EN

Architecture de Mia

Vue technique condensée : instantané système, boucle temps réel, métriques, validation, positionnement. Active le mode ingénieur (bouton en haut à droite) pour afficher les données, logs et schémas bruts.

01Instantané système

Mia est un système de robotique cognitive temps réel combinant une tête robotique physique avec une architecture cognitive modulaire à base d'agents.

Hardware

  • 28 servomoteurs (actionneurs faciaux)
  • Structure mécanique sur mesure (imprimée 3D + peau latex)
  • Contrôle moteur par microcontrôleur

Calcul

  • Runtime : CPU seul — PC modeste, sans GPU
  • Latence de boucle : ~350 ms (perception → décision → actionnement)

Architecture

  • 6 engines centraux : perception, mémoire, arbitrage, planification, exécution, contrôle moteur
  • 109 agents cognitifs (modules spécialisés)

Entrées

  • Vision (caméra)
  • État interne
  • Texte (optionnel)

Sorties

  • Commandes motrices (expressions faciales)
  • Texte (dialogue)
  • Mises à jour de l'état interne

Runtime

  • Boucle continue (temps réel)
  • Mémoire persistante activée
snapshot.json# exemple de snapshot système — instant t { "timestamp": "2026-04-24T14:32:07.142Z", "uptime_s": 18432, "tick": 52663, "runtime": { "loop_latency_ms": 347, "cpu_load_pct": 41, "gpu": null, "memory_mb": 312 }, "engines": { "perception": { "status": "running", "last_tick_ms": 38 }, "memory": { "status": "running", "last_tick_ms": 81 }, "arbitration": { "status": "running", "last_tick_ms": 92 }, "planning": { "status": "running", "last_tick_ms": 88 }, "execution": { "status": "running", "last_tick_ms": 47 }, "motor_control": { "status": "running", "last_tick_ms": 31 } }, "agents": { "total": 109, "active_this_cycle": 42, "top_contributors": [ "face_detector", "gaze_tracker", "affect_updater", "decision_scorer", "motor_coordinator" ] }, "internal_state": { "mode": "vigilance", "valence": -0.08, "arousal": 0.41, "climate": "attente calme", "focus": "single_face", "inhibition": 0.62 }, "inputs": { "camera_fps": 24, "faces_detected": 1, "text_input": null }, "outputs": { "motor_channels_active": 6, "current_expression": "micro_smile", "dialogue_queue": 0 } }

02Vue d'ensemble de l'architecture

Mia fonctionne comme une boucle continue perception → décision → action.

Diagramme d'architecture de Mia : entrée caméra, architecture cognitive (engines perception, mémoire, arbitrage, planification, exécution), couche physique (contrôle moteur vers 28 servos), avec boucle de retour vers la mémoire.
Flux caméra → cognition → moteurs, avec boucle de retour vers la mémoire.

Engine de perception

Traite les entrées visuelles et extrait des signaux structurés.

Engine de mémoire

Maintient l'état interne persistant et les expériences passées.

Engine d'arbitrage

Sélectionne les signaux pertinents et résout les entrées concurrentes.

Engine de planification

Génère des actions candidates à partir de l'état courant.

Engine d'exécution

Transforme les décisions en commandes actionnables.

Engine de contrôle moteur

Traduit les commandes en mouvements synchronisés des servomoteurs.

Topologie système — vue labo, analogue à un graphe ROS (l'app n'utilise pas ROS — c'est juste la convention de lecture)
                                    ┌─────────────────────────────────────────┐
                                    │            MONDE PHYSIQUE               │
                                    │   (Zan, personnes, environnement)       │
                                    └────────────┬──────────────┬─────────────┘
                                                 │ lumière      │ voix
                                                 ▼              ▼
                ┌──────────────────────┐   ┌──────────────────────┐       ┌──────────────────┐
                │  ESP32-CAM #1 œil G  │   │  ESP32-CAM #2 œil D  │       │  Micro (STT ?)   │
                │  192.168.1.14/capture│   │  192.168.1.15/capture│       │  (non implémenté)│
                │  JPEG over HTTP      │   │  JPEG over HTTP      │       └──────────────────┘
                └───────────┬──────────┘   └──────────┬───────────┘
                            │ JPEG                    │ JPEG
                            └────────────┬────────────┘
                                         ▼
 ╔══════════════════════════════════════════════════════════════════════════╗
 ║   PERCEPTION SERVICE (Python, process séparé, FastAPI/Uvicorn)           ║
 ║   ─────────────────────────────────────────────────────────────────      ║
 ║                                                                          ║
 ║   POST /analyze-image                                                    ║
 ║      ┌─────────────┐   ┌────────────────┐   ┌────────────────┐           ║
 ║      │  OpenCV     │──▶│  InsightFace   │──▶│  MediaPipe     │           ║
 ║      │  décodage   │   │  buffalo_l     │   │  FaceLandmarker│           ║
 ║      │  BGR↔RGB    │   │  RetinaFace +  │   │  478 landmarks │           ║
 ║      │             │   │  ArcFace 512-D │   │  52 blendshapes│           ║
 ║      └─────────────┘   └───────┬────────┘   └───────┬────────┘           ║
 ║                                │ embeddings         │ blendshapes        ║
 ║                                ▼                    ▼                    ║
 ║                        ┌───────────────────────────────┐                 ║
 ║                        │  FaceRegistry (identités)     │                 ║
 ║                        │  stockage local disque        │                 ║
 ║                        └───────────────────────────────┘                 ║
 ║   POST /register-face    GET /persons   DELETE /persons/{id}   /health   ║
 ╚═══════════════════════╤══════════════════════════════════════════════════╝
                         │ JSON  (faces[], landmarks[], blendshapes[])
                         │ HTTP localhost
                         ▼
 ╔══════════════════════════════════════════════════════════════════════════════════╗
 ║   RUNTIME COGNITIF (.NET 9, ASP.NET Core, BackgroundService)                     ║
 ║   ─────────────────────────────────────────────────────────────────────────      ║
 ║                                                                                  ║
 ║          ┌────────────────────────────────────────────────────┐                  ║
 ║          │  CognitiveRuntimeHostedService                     │                  ║
 ║          │  PeriodicTimer 350 ms  ─▶ TickAsync()              │                  ║
 ║          └──────────────────────┬─────────────────────────────┘                  ║
 ║                                 │  snapshot (unique, passé à tous)               ║
 ║                                 ▼                                                ║
 ║   ┌──────────────┐   ┌─────────────────┐   ┌─────────────────┐   ┌─────────────┐ ║
 ║   │ SceneEngine  │──▶│ MorphologyEngine│──▶│ GeneratorEmerg. │──▶│IntentionArb.│ ║
 ║   │ (entrées     │   │ (dominance,     │   │ Engine          │   │ Engine      │ ║
 ║   │  perçues)    │   │  inhibition,    │   │ (formes         │   │ (scoring    │ ║
 ║   │              │   │  valence)       │   │  internes)      │   │  pondéré +  │ ║
 ║   └──────────────┘   └─────────────────┘   └─────────────────┘   │  jitter)    │ ║
 ║                                                                   └──────┬──────┘ ║
 ║   109 agents (en parallèle, séquentiels dans le tick) :                  │        ║
 ║    • affectifs • normatifs • identitaires • sociaux • mémoriels          │        ║
 ║    • ponts (bridge)  • révisions                                         │        ║
 ║                                                                   intention gagnante ║
 ║   ┌────────────────────────────┐      ┌───────────────────────┐          │        ║
 ║   │ ReinforcementLearningEngine│◀─────│ CognitiveActionOutcome│          │        ║
 ║   │ 10 features → 7 poids      │      │ (success/partial/fail,│          │        ║
 ║   │ REINFORCE, ε-greedy        │      │  focus error, etc.)   │          │        ║
 ║   │ buffer 64 exp, LR=0.005    │      └───────────────────────┘          │        ║
 ║   └──────────┬─────────────────┘                                         │        ║
 ║              │ gains multiplicatifs (Arbitration*Gain)                   │        ║
 ║              └──────────────────────────────────────────┐                │        ║
 ║                                                          ▼                ▼        ║
 ║                                        ┌─────────────────────────────────────┐    ║
 ║                                        │  ActionExecutor                     │    ║
 ║                                        │  + SpeechOutputAgent                │    ║
 ║                                        └────────┬───────────────┬────────────┘    ║
 ╚══════════════════════════════════════════════════╧═══════════════╧═════════════════╝
                           │ état + commandes                 │ texte à dire
                           │ (SignalR hub /cognitive-hub)     │
                           │                                  ▼
                           │                      ┌───────────────────────┐
                           │                      │  CognitiveLlmService  │
                           │                      │  (prothèse langage)   │
                           │                      │  • HTTP transport     │
                           │                      │  • CLI transport      │
                           │                      │    (subprocess)       │
                           │                      └───────────┬───────────┘
                           │                                  │ prompt / réponse
                           │                                  ▼
                           │                      ┌───────────────────────┐
                           │                      │  API Claude           │
                           │                      │  (modèle externe)     │
                           │                      │  RAM only, éphémère   │
                           │                      └───────────────────────┘
                           │
      ┌────────────────────┼──────────────────────────────────────────────────────┐
      ▼                    ▼                                                      ▼
  ┌──────────────┐   ┌──────────────────┐                             ┌─────────────────────┐
  │ FRONT SPA    │   │  HARDWARE BRIDGE │                             │  PERSISTANCE        │
  │ JS vanilla   │   │  ──────────────  │                             │  ─────────────      │
  │ modules ES   │   │ • Série COM5     │                             │ 14 stockages :      │
  │ wwwroot/     │   │   → Arduino Mega │                             │ • SQLite (migration │
  │ Cockpit,     │   │     2560         │                             │   en cours : RL…)   │
  │ Corps, IA,   │   │   → 27 servos    │                             │ • JSON atomique     │
  │ Mémoire…     │   │ • HTTP ESP32     │                             │   (.tmp → move +    │
  │ SignalR +    │   │ • ROS-like sur   │                             │    .bak)            │
  │ REST         │   │   RPi5 ???       │                             │ • knowledge.json    │
  └──────────────┘   └─────────┬────────┘                             │ • cognitive-state   │
                               │ PWM / ordres                         │ • episodes…         │
                               ▼                                      └─────────────────────┘
                     ┌──────────────────┐
                     │ Servos physiques │
                     │ (tête, yeux, cou,│
                     │  mâchoire,       │
                     │  langue, lèvres) │
                     └──────────────────┘

      ════════════════════════════════════════════════════════════════════════════
      FLUX NOMMÉS (analogues à des topics ROS)
      ════════════════════════════════════════════════════════════════════════════
      /vision/frame            JPEG brut ESP32 → .NET
      /vision/analysis         JSON faces+landmarks+id   Python → .NET
      /cognitive/tick          snapshot interne, in-process, 350 ms
      /cognitive/arbitration   candidats + vainqueur
      /cognitive/rl/update     (features, reward)        post-tick
      /action/execute          intention → commandes

ESP32 en Wi-Fi HTTP (latence réseau), Arduino en série (latence ms). Raspberry Pi 5 pas encore intégré au pipeline — rôle à définir (probable hub vision local ou orchestrateur bas niveau).

Pas de ROS, pas de DDS, pas de broker : toute l'IPC inter-processus est HTTP REST. Délibérément simple, au prix d'un plafond ~3 fps pour la vision lourde — largement suffisant ici.

RL dans la boucle : le seul « apprentissage » qui modifie vraiment le comportement tourne sur 7 poids scalaires — encart gauche, mis à jour après chaque action.

LLM hors persistance : volontairement détaché du graphe de mémoire — il parle, il ne laisse pas de trace.

architecture.schema# dataflow — camera → cognition → motors → feedback ┌───────────────────┐ │ Camera Input │ └─────────┬─────────┘ │ ▼ ╔═════════════════════════════════════════════════════════════════╗ ║ COGNITIVE ARCHITECTURE ║ ║ ║ ║ ┌──────────────┐ ║ ║ │ Perception │ extract structured signals ║ ║ └──────┬───────┘ ║ ║ ▼ ║ ║ ┌──────────────┐ ║ ║ │ Memory │ ◄─────────────── feedback ◄─────────┐ ║ ║ │ (persistent) │ internal state · past experience │ ║ ║ └──────┬───────┘ │ ║ ║ ▼ │ ║ ║ ┌──────────────┐ │ ║ ║ │ Arbitration │ resolve competing signals │ ║ ║ └──────┬───────┘ │ ║ ║ ▼ │ ║ ║ ┌──────────────┐ │ ║ ║ │ Planning │ generate candidate actions │ ║ ║ └──────┬───────┘ │ ║ ║ ▼ │ ║ ║ ┌──────────────┐ │ ║ ║ │ Execution │ turn decisions into commands │ ║ ║ └──────┬───────┘ │ ║ ║ │ │ ║ ╚═══════════════╪═════════════════════════════════════════════╪═══╝ │ │ ▼ │ ╔═════════════════════════════════════════════════════════════════╗ ║ PHYSICAL LAYER ║ ║ ║ ║ ┌──────────────────┐ ║ ║ │ Motor Control Engine │ synchronize servo channels ║ ║ └──────────┬───────────┘ ║ ║ ▼ ║ ║ ┌────────────────────────┐ ║ ║ │ Robot Face (28 servos) │ ──── proprioceptive feedback ─┘ ║ └────────────────────────┘ ║ ║ ║ ╚═════════════════════════════════════════════════════════════════╝ # loop: ~350 ms per full pass · continuous · CPU-only # agents: 109 task-specific modules distributed across the 6 engines

Mia a une proprioception extéroceptive (webcam → MediaPipe blendshapes sur son propre visage), pas d'encodeurs internes — ça recadre l'analyse vers un pattern self-model visuel plutôt que robotique classique.

03Fondements formels

Traduction L3 de l'architecture ci-dessus : état vectoriel, fonction de transition, politique de mémoire, frontière LLM. Tous les poids du scoring restent auditables dans le code — aucun gradient ne bouge de manière opaque.

État du système

St = ( Pt, Mt, At, It, Dt, Xt )
  • Pt — features perceptives (landmarks, identité face, contexte scène)
  • Mt — snapshot mémoire (14 domaines cognitifs typés, persistés JSON)
  • At — affect (valence, arousal, climat cognitif)
  • It — inhibitions actives (cooldown, normes, sécurité)
  • Dt — décision courante
  • Xt — plan d'exécution en attente

Dynamique & politique

S(t+1) = f( S(t), perception(t), memory(t) )
action(t) = π( S(t) )

Deux équations pour deux rôles distincts :

  • fdynamique du système. L'état à t+1 dépend de l'état courant, de la perception fraîche (frame caméra) et d'une lecture de la mémoire.
  • πpolitique d'arbitrage. Produit l'action à partir de l'état. Détail au bloc Arbitrage.

Période d'évaluation : 350 ms (.NET, soft real-time).

f est déterministe. π est déterministe sauf en un point unique : stochasticité contrôlée quand le top et le second sont trop proches (|top − second| < 0.12).

Les coefficients de f et π restent fixes à l'exécution. Seuls 5 gains multiplicatifs globaux de π sont appris, via un RL minimal borné et désactivable (voir bloc Apprentissage).

Mémoire — 14 domaines typés

Pas de graphe universel. Pas de base vectorielle. Mt est un tuple de 14 domaines cognitifs, chacun avec son schéma et son repository JSON : JsonCognitive<Domain>Repository.cs.

Écritures possibles dans Mt :

  • Implicite — moyenne mobile exponentielle (EMA) des succès par pattern (SuccessBiasScore, AttractorBiasScore via MemoryContribution)
  • Explicite — commande teachknowledge.json
  • Narrativejournal-conversations.md

Oubli : décroissance exponentielle naturelle de l'EMA. Pas de purge.
Retrieval : clé directe par domaine. Pas de nearest-neighbor générique — chaque domaine a son API typée.

Apprentissage — RL minimal et auditable

Oui, il y a du reinforcement learning — mais pas ce qu'on pourrait craindre. CognitiveLearningService + JsonCognitiveRLRepository implémentent un policy gradient ultra-léger :

  • 7 poids scalaires ajustés (dont les 5 Arbitration*Gain)
  • 10 features en entrée
  • Update trivial en ~3 lignes de code
  • Exploration bornée par construction (clamp min/max sur chaque poids)
  • Pas de réseau de neurones, pas de gradient opaque, pas de tenseurs

Ce que le RL touche : les 5 gains multiplicatifs globaux de l'arbitrage, appliqués au profil via ApplyToProfile(profile). En parallèle, MemoryContribution maintient des biais statistiques (SuccessBiasScore, AttractorBiasScore) moyennés exponentiellement.

Ce que le RL ne touche pas : les poids atomiques du scoring (× 0.35, × 0.07…), la structure de T, l'extraction des features. Tout ça reste hardcodé et lisible.

L'apprentissage agit sur un seul étage : cinq gains multiplicatifs globaux.
Tout le reste du scoring reste fixe et auditable dans le code.

Kill-switch : SetEnabled(false) → tous les gains reviennent à 1.0 → l'arbitrage redevient purement heuristique. L'opérateur garde le contrôle manuel à chaud.

Arbitrage

Score multi-critère par action candidate :

score(ai) = Σk gk · ( Σj∈k wj · fj( St, ai ) )

Où :

  • wj — poids atomiques fixes (dans le code)
  • gk5 gains multiplicatifs globaux (Arbitration*Gain), appris par RL, bornés, désactivables (gk = 1.0 si SetEnabled(false))
  • fj — features observées + biais mémoire via EMA

Règle d'arbitrage :

  • Si |top − second|0.12argmax (déterministe)
  • Sinon → échantillonnage pondéré parmi le top-k proche (stochasticité contrôlée)

Le seuil 0.12 modélise une incertitude irréductible : quand deux options sont trop proches, refuser de trancher arbitrairement est en soi une décision.

Frontière LLM — point différenciateur

Le LLM est hors de T, hors de S, hors du substrat. Ce n'est ni un engine, ni un agent, ni un composant de mémoire.

Il reçoit les sorties narratives de Mia et produit du langage en retour. Session non persistée (--no-session-persistence).

Deux canaux (et seulement deux) sont autorisés pour écrire dans Mt :

  1. teachknowledge.json — apprentissage explicite, sous contrôle humain
  2. journal-conversations.md — écriture narrative, relue par Mia lors des cycles suivants

Conséquence : le LLM peut être changé (v1 → v2, fournisseur A → B) sans altérer le substrat. Mia reste Mia entre les générations de LLM.

04Agents cognitifs

Un agent est un module computationnel spécialisé, avec des entrées et sorties définies.

Exemples

  • Agent de détection de visage
  • Agent de mise à jour de l'état émotionnel
  • Agent de notation de décision
  • Agent de coordination motrice
Structure interne d'un engine : une pile d'agents orchestrés
ENGINE (ex. Perception)

┌─────────────────────────────┐
│         ENGINE CORE         │
│                             │
│   ┌───────────────┐         │
│   │   Agent 1     │         │
│   ├───────────────┤         │
│   │   Agent 2     │         │
│   ├───────────────┤         │
│   │   Agent 3     │         │
│   ├───────────────┤         │
│   │     ...       │         │
│   ├───────────────┤         │
│   │   Agent N     │         │
│   └───────────────┘         │
│                             │
└─────────────────────────────┘

Les agents sont orchestrés à l'intérieur des engines et interagissent via un état partagé.

agents.manifest — 109 modules# task-specific modules, grouped by hosting engine [perception] (23 agents) face_detector · haar + CNN hybrid face_tracker · inter-frame association gaze_estimator · pupil + iris geometry head_pose_estimator · 6-DoF from landmarks landmark_68_extractor · dlib shape predictor distance_estimator · monocular depth cue presence_detector · motion + face combined luminance_monitor · exposure feedback ... (+15 more) [memory] (19 agents) short_term_buffer · 5s rolling window long_term_consolidator · nightly sleep cycle episodic_recorder · tagged event store face_identity_bank · known-faces registry affect_tonality_tracker · baseline valence/arousal salience_weighter · recency × intensity ... (+13 more) [arbitration] (22 agents) candidate_collector · merge engine proposals decision_scorer · multi-factor scoring tie_breaker_random · controlled stochasticity inhibition_regulator · blocks risky outputs norm_checker · behavioral guardrails cooldown_guard · prevents oscillation ... (+16 more) [planning] (18 agents) motor_plan_composer · sequence of servo moves expression_selector · pick from affect library dialogue_drafter · LLM async bridge timing_planner · dispatch schedule ... (+14 more) [execution] (15 agents) command_serializer · binary wire format channel_router · servo vs text vs memory ack_collector · waits for confirmations ... (+12 more) [motor_control] (12 agents) servo_driver_lip · 3 channels servo_driver_brow · 4 channels servo_driver_eyelid · 2 channels servo_driver_eye · 6 channels (x + z) servo_driver_jaw · 1 channel servo_driver_tongue · 3 channels servo_driver_neck · 3 channels proprioceptive_reader · reports executed state ... (+4 more) total = 109

05Boucle temps réel

Cycle typique observé :

  1. t = 0 msImage capturée (caméra)
  2. t = 40 msVisage détecté
  3. t = 120 msÉtat interne mis à jour
  4. t = 210 msDécision choisie (ex. « sourire »)
  5. t = 300 msCommandes motrices générées
  6. t = 350 msExpression faciale exécutée
runtime.log — tick 52663# single cognitive cycle — 347 ms end-to-end [14:32:06.795] boot runtime started · 6 engines online · 109 agents loaded [14:32:07.142] tick 52663 │ cycle start [14:32:07.142] t+000ms perception camera_frame_captured res=640x480 fps=24 [14:32:07.182] t+040ms perception face_detected bbox=234,156,310,260 conf=0.94 [14:32:07.222] t+080ms memory context_enriched faces=1 last_seen=2.1s [14:32:07.262] t+120ms memory internal_state_updated valence=-0.08 arousal=0.41 climate="calm waiting" [14:32:07.352] t+210ms arbitration decision_selected action="micro_smile" score=0.72 (over 4 candidates) [14:32:07.442] t+300ms planning motor_plan_generated channels=6 duration=180ms [14:32:07.492] t+350ms execution motor_commands_dispatched → motor_control [14:32:07.495] t+353ms motor_control servos_driven [lip_L, lip_R, brow_L, brow_R, eyelid_L, eyelid_R] [14:32:07.498] t+356ms memory proprioceptive_feedback_received expression="micro_smile" executed=true [14:32:07.489] tick 52663 │ cycle end · latency=347ms · agents_active=42/109 [14:32:07.489] tick 52664 │ cycle start [14:32:07.489] t+000ms perception camera_frame_captured res=640x480 fps=24 [14:32:07.530] t+041ms perception face_tracked bbox=236,155,311,261 conf=0.95 [14:32:07.571] t+082ms memory continuity_detected same_face duration=0.9s [14:32:07.611] t+122ms memory internal_state_updated valence=-0.05 arousal=0.44 [14:32:07.700] t+211ms arbitration decision_selected action="hold_gaze" score=0.81 [14:32:07.790] t+301ms planning motor_plan_generated channels=2 duration=0ms (hold) [14:32:07.840] t+351ms execution motor_commands_dispatched → motor_control [14:32:07.836] tick 52664 │ cycle end · latency=347ms · agents_active=39/109

06Démonstration en direct

Le système tourne en continu dans une boucle fermée perception–action.

Interaction typique

  1. Un stimulus visuel est détecté
  2. L'état interne évolue
  3. Une réponse comportementale est générée
  4. Les moteurs exécutent l'expression correspondante

07Métriques système

Latence de boucle

  • Moyenne : ~350 ms

Stabilité runtime

  • Fonctionnement continu : testé sur sessions étendues

Actionnement

  • 28 canaux servomoteurs synchronisés

Architecture

  • 109 agents actifs
  • 6 engines coordonnateurs
metrics.raw — last 5h session# measured metrics (uptime=5h 07min · tick=52663) loop_latency_ms p50=342 p75=349 p95=368 p99=391 max=427 cpu_load_pct avg=41 peak=58 (single CPU, no GPU) memory_mb rss_avg=312 rss_peak=384 heap_live=207 agents_firing_per_cycle avg=38 median=42 max=61 / 109 cycles_completed total=52663 rate=3.0/s drift_ms/hour=<1 frames_dropped last_hour=0 lifetime=3 servo_channels active_avg=4.2 stall_events=0 proprio_feedback_ok=100% errors_last_24h engine_crashes=0 agent_timeouts=2 recovered=2

08Approche de validation

Mia est conçue pour être testable et reproductible.

Validation future

  • Expériences comportementales reproductibles
  • Latence de réponse mesurable
  • Stabilité du système en fonctionnement continu

L'objectif est de passer de la démonstration à l'évaluation rigoureuse.

09Positionnement

Mia n'est pas un système basé sur un modèle de langage. C'est une architecture cognitive incarnée temps réel combinant perception, état interne et actionnement physique.

Être prévenu·e du lancement

Deux campagnes crowdfunding bientôt — laisse ton email, on te prévient au lancement.

Quelle(s) campagne(s) ?