Ce qui se passe
Le constat de départ est juste, et il vaut pour n'importe quel agent de code : lire l'intégralité du code source ne dit rien de ce qui s'est passé à la dernière requête. Quelle requête SQL était lente, ce que le profiler a enregistré il y a cinq minutes, quel service a réellement été instancié. Le code décrit une capacité ; le runtime décrit un fait.
Mate ouvre cette porte. Il a commencé comme serveur MCP exposant les internes d'une application Symfony à un agent. Depuis Symfony AI 0.13, c'est une simple ligne de commande avec une couche de découverte : aucun processus à faire tourner, aucune poignée de main protocolaire.
Ce que l'agent peut demander
Chaque commande fait une seule chose :
| Commande | Réponse |
|---|---|
symfony-profiler-list / symfony-profiler-get |
lister les profils récents filtrés par méthode, URL ou code de statut, puis en récupérer un par son jeton avec ses collecteurs |
monolog-tail / monolog-search |
« qu'est-ce qui vient de casser », en requête filtrée par niveau, canal et environnement, au lieu d'un grep dans un fichier |
symfony-service-detail |
classe réelle d'un service, tags de DI, appels de méthode configurés, factory qui le construit |
Le choix d'implémentation mérite d'être noté : Mate lit les artefacts que Symfony écrit déjà sur disque — conteneur compilé, stockage du profiler, fichiers de log — plutôt que de démarrer l'application. Le bénéfice apparaît dans le pire cas : quand un conteneur cassé est précisément la raison pour laquelle l'application ne démarre plus, Mate peut encore inspecter le dernier conteneur correctement écrit.
La partie qui compte : la découverte
Des commandes présentes sur le disque ne sont pas des commandes qu'un agent sait utiliser. C'est le vrai chantier de la 0.13, après l'abandon du serveur MCP.
mate init demande comment l'agent doit invoquer Mate — directement, via
docker exec <conteneur>, ddev exec ou équivalent — et enregistre la réponse
avec la version de PHP utilisée. Ce n'est pas cosmétique : l'enveloppe
d'invocation devient une partie des instructions transmises à l'agent, et la
version de PHP sert de garde-fou. Si Mate démarre sous un autre PHP majeur ou
mineur, il refuse de continuer.
Ensuite, mate init et mate discover écrivent des instructions dans un bloc
géré de votre AGENTS.md, avec un CLAUDE.md qui l'importe.
Les skills portent le reste — non pas qu'une commande existe, mais quand y
recourir. Cinq sont livrées : débogage via le profiler, investigation de logs,
triage de requête, inspection de service et vérification de l'environnement PHP,
complétées par system-information pour les versions de paquets. Elles ont un
cycle de vie : skills:enable / skills:disable pour en couper une sans la
retirer, skills:override / skills:reset pour l'adapter à une règle maison
puis revenir à la version livrée.
Ajouter ses propres outils
L'ensemble est extensible avec un seul attribut, posé sur une méthode :
#[MateTool(name: 'deploy-status')]
public function deployStatus(string $environment): string
{
// La réflexion et le PHPDoc produisent le schéma d'entrée :
// l'agent reçoit un contrat typé, sans câblage supplémentaire.
}Seul name est obligatoire ; title et description aident l'agent à décider
si l'outil répond à sa question. La classe va dans mate/src/, que mate init
enregistre sous le namespace Mate\, et l'outil apparaît dans tools:list à
l'exécution suivante — aucune définition de service à écrire.
#[MateResource] et #[MateResourceTemplate] couvrent les données qu'un agent
lit plutôt qu'il n'invoque : un changelog, une page d'état.
Pour mutualiser entre projets, l'organisation MatesOfMate rassemble un
gabarit d'extension et des intégrations PHPUnit, PHPStan, Rector et Composer ;
une extension livre ses propres skills via extra.ai-mate.skills.
À retenir
composer require --dev symfony/ai-mate
vendor/bin/mate initMate ne fabrique aucune information nouvelle : il ouvre à l'agent ce que le profiler et le logger savaient déjà, au lieu de le laisser deviner en lisant cinq fichiers. Pour qui travaille avec un agent sur une application Symfony, c'est le chaînon qui manquait entre « lire le code » et « savoir ce qui s'est passé ».