LeaSH: et si le shell était l'interface des agents IA ?
TL;DR: LeaSH est un moteur d’exécution shell sandboxé qui s’expose via MCP. L’idée : au lieu d’offrir à un LLM une centaine d’outils atomiques qui saturent sa fenêtre de contexte, on lui donne un shell contrôlé où il peut composer, enchaîner et filtrer lui-même. C’est une expérimentation, pas une solution définitive, mais les premiers résultats sont encourageants.
Le problème : trop d’outils tuent l’outil
Cloudflare a posé le diagnostic dans son article sur le Code Mode : le protocole MCP a beau être devenu le standard pour connecter des agents à des outils externes, chaque outil ajouté consomme des tokens de contexte. Décrivez cent endpoints d’API et il ne reste plus grand-chose pour la tâche elle-même.
Leur solution — baptisée Code Mode — consiste à remplacer la liste d’outils par un SDK typé et un bac à sable d’exécution. Le modèle écrit du code TypeScript, l’exécute dans un Worker isolé, et ne renvoie que le résultat utile. Anthropic a convergé indépendamment vers la même idée dans son billet Code Execution with MCP.
Un sujet périphérique fait également débat dans la communauté: faut-il exposer des outils MCP atomiques ou des skills qui encapsulent la logique d’orchestration ?
Je ne crois pas qu’il y ait de réponse universelle. Et en ce sens, LeaSH n’essaie pas de le trancher: en donnant à l’agent un langage de composition plutôt qu’une liste de fonctions, il conserve la flexibilité et l’auditabilité des outils tout en réduisant leur empreinte sur le contexte.
De manière empirique, le constat m’apparaît juste. Mais la réponse m’a donné envie d’explorer une variante : pourquoi pas le shell ? Les LLM savent déjà en écrire. Le shell est un langage de composition — pipes, redirections, boucles, tout ce qu’il faut pour chaîner des opérations existe depuis cinquante ans. Il manquait peut-être juste une pièce : un moyen de laisser un agent écrire du shell sans lui donner les clés de la machine.
C’est l’hypothèse que LeaSH essaie de vérifier.
LeaSH : un shell audité comme plan d’exécution
LeaSH reprend l’intuition du Code Mode et la transpose dans l’univers Unix. C’est un moteur d’exécution shell qui applique une politique de sécurité stricte à chaque script, avant et pendant l’exécution :
- Filtrage par patterns — les motifs dangereux (
rm -rf /,dd if=,mkfs…) sont détectés par pattern matching après l’interpolation des variables pour éviter les contournements. - Validation AST — une fois le script parsé, on borne le nombre de commandes, la profondeur de sous-shells, les jobs en arrière-plan, etc.
- Allowlist de binaires — seuls les exécutables explicitement déclarés dans la politique sont accessibles. Le reste retourne un code 127, sans jamais toucher l’OS.
- Isolation d’environnement — aucune variable du système hôte ne fuit. Pas de
$HOMEréel, pas de token AWS qui traîne, pas de$PATHsystème. - Sandbox OS — en option, les commandes s’exécutent dans un sandbox bubblewrap (
bwrap) ou chroot : montages en lecture seule, système de fichiers en mémoire, isolation du réseau et des processus. - Rate limiting, timeout, audit — chaque commande est enregistrée avec son code de sortie, sa durée et sa raison de blocage éventuelle. Le tout en JSON structuré.
Le pari : un agent peut écrire grep ERROR /var/log/app.log | sort | uniq -c | head -20 et obtenir exactement ce qu’il cherche en un seul appel MCP. Pas besoin de cinq outils séparés (read_file, filter_lines, sort_output, count_unique, limit_results). Le shell fait le travail — en théorie, du moins.
Un seul outil MCP
Côté MCP, LeaSH a simplifié son interface au maximum : un seul outil est exposé.
execute_shell— exécute un script dans le bac à sable et renvoie stdout, stderr et le code de sortie et la liste des commandes bloquées (le cas échéant).
Le manifeste des commandes disponibles (binaires autorisés, builtins enregistrés) est injecté directement dans le system prompt de l’agent au moment de la connexion. Concrètement, l’agent reçoit quelque chose comme :
LeaSH is a policy-enforced shell sandbox.
## The ONLY MCP tool is: execute_shell
There is exactly one MCP tool: execute_shell. Do NOT attempt to call any
other name as an MCP tool. All operations are performed by passing shell
scripts to execute_shell.
## Available shell commands
(These are shell commands — invoke them via execute_shell, NOT as MCP tools)
- grep (system binary)
- sed (system binary)
- awk (system binary)
- sort (system binary)
[...]
Any other command will be blocked (exit code 127).
À partir de là, un appel typique ressemble à :
{
"tool": "execute_shell",
"arguments": {
"script": "grep -r 'TODO' src/ | wc -l"
}
}
Et la réponse:
## STDOUT
42
## EXIT CODE
0
Comparez avec le coût en tokens d’une déclaration MCP classique exposant read_file, list_directory, count_lines, search_pattern**… On voit immédiatement où va le budget de contexte.
Cas concret : un agent d’audit de code
Pour tester l’idée dans des conditions réalistes, j’ai construit audit-bot, un agent autonome de revue de sécurité qui s’appuie exclusivement sur LeaSH. La politique est volontairement restrictive : lecture seule, seulement quelques binaires d’exploration (grep, find, cat, ls). L’agent ne peut que lire le code, jamais le modifier ni exécuter quoi que ce soit d’arbitraire.
# Audit d'un projet
PROJECT_DIR=/chemin/vers/mon/projet make audit
# Spécifier le langage/framework
PROJECT_DIR=/chemin/vers/mon/projet LANGUAGES="Python Django" make audit
Le rapport est généré dans un fichier report_<timestamp>.md et suit une méthodologie en six phases : reconnaissance, modélisation des menaces, analyse des vulnérabilités, revue adversariale, validation, rapport. À titre d’exemple, un extrait de sortie ressemble à:
## Vulnérabilités identifiées
### [HIGH] Injection SQL potentielle — src/Repository/UserRepository.php:142
La méthode `findByEmail()` concatène directement `$email` dans une requête native :
$sql = "SELECT * FROM users WHERE email = '" . $email . "'";
Aucun binding de paramètre n'est utilisé. Exploitable si `$email` provient
d'une entrée utilisateur non filtrée (cf. UserController:78).
Recommandation : utiliser `createQueryBuilder()` ou un prepared statement.
Ce qui est intéressant ici, c’est la combinaison : un agent entièrement autonome, des outils réduits à l’essentiel, et une surface d’attaque maîtrisée. L’agent ne peut pas “sortir” du sandbox, modifier des fichiers. Il est contraint à faire exactement ce pour quoi il a été configuré.
En pratique
LeaSH s’utilise de trois manières:
# REPL interactif — pour tester et déboguer
./leash --policy policies/default.yaml repl
# Exécution ponctuelle — pour le scripting
./leash --policy policies/default.yaml exec --exec 'echo hello | tr a-z A-Z'
# Serveur MCP — pour les agents
./leash --policy policies/default.yaml mcp stdio
Les politiques fournies couvrent les principaux cas d’usage :
| Politique | Usage type |
|---|---|
default |
REPL interactif de développement, exploration locale |
restrictive |
Traitement de logs ou de fichiers texte en production |
sandboxed |
Agent autonome opérant sur du code ou des données non-trusted |
Le mode mcp stdio s’intègre directement dans la configuration de n’importe quel client MCP (Claude Desktop, genai, etc.):
{
"mcpServers": {
"leash": {
"command": "/path/to/leash",
"args": ["--policy", "/path/to/policy.yaml", "mcp", "stdio"]
}
}
}
Limites et questions ouvertes
L’approche a des limites évidentes qu’il serait malhonnête de taire :
- Pas de parallélisation. Le shell exécute séquentiellement. Le Code Mode de Cloudflare, en s’appuyant sur JavaScript, permet à l’agent de lancer plusieurs appels API en parallèle (
Promise.all). Avec LeaSH, chaque commande attend la fin de la précédente. Pour des scénarios impliquant beaucoup d’appels réseau indépendants, c’est un handicap réel. - Fragilité du parsing textuel. Le shell compose des flux de texte. Quand une commande change son format de sortie, le pipe suivant casse silencieusement. Un SDK typé offre des garanties que
grep | awk | cutne donnera jamais. - Surface de sécurité. Malgré les couches de protection (validation AST, allowlist, sandbox bubblewrap), le shell reste un langage puissant avec des recoins surprenants. La surface d’attaque est intrinsèquement plus large qu’un SDK contrôlé.
- Maturité. LeaSH est un projet jeune. Les politiques de sécurité n’ont pas encore été éprouvées dans des contextes de production variés. L’audit trail est là, mais il reste du travail pour que l’ensemble inspire une confiance suffisante pour des environnements critiques.
Une piste, parmi d’autres
Le Code Mode de Cloudflare a raison sur le fond: donner à un agent un langage de programmation plutôt qu’une liste d’outils est plus efficace et plus économe en tokens. LeaSH explore une variante en partant d’un autre dénominateur commun: le shell. Tous les serveurs Unix l’ont, les LLM savent en écrire, et son modèle de composition (stdin → stdout, pipes, codes de retour) est immédiatement accessible à un agent.
Est-ce que c’est la bonne réponse ? Probablement pas partout. Mais pour des tâches d’administration système, de diagnostic ou de traitement de texte — là où les outils Unix brillent depuis des décennies — l’hypothèse mérite d’être creusée.
N’hésitez pas à venir en discuter si le sujet vous intéresse.