navigation
TX 004

pi : pourquoi j'ai fait de cet agent de codage mon quotidien

Retour d'expérience sur pi, le harness d'agent de codage model-agnostic : skills, subagents, mémoire cross-session, config pilotée par dotfiles.

9 min de lecture

IDE plugins vs terminal : pourquoi un harness, pas un chatbot

Pendant des mois, j’ai enchaîné les plugins d’IDE dits « IA » — Cursor, Cline, les extensions VS Code de toutes marques. Le constat revient toujours : le contexte reste enfermé dans l’éditeur, impossible à scripter, impossible à réutiliser d’une session à l’autre. On pestait contre un hallucinage, on rouvrait un nouvel onglet, on repartait de zéro. Un chatbot greffé sur un éditeur, ça reste un chatbot.

La distinction qui a changé ma façon de travailler : un chatbot répond, un harness orchestre. Un harness ne se contente pas de générer du texte — il donne à l’agent des outils, des skills, une mémoire persistante, et la capacité de déléguer à d’autres agents spécialisés. C’est un atelier, pas une boîte de dialogue.

C’est là que pi est entré dans mon quotidien : un harness CLI-native, model-agnostic, que je configure comme je configure mes dotfiles. Cet article est un retour d’expérience praticien — pas une pub, j’aborde aussi les limites à la fin.

Ce qu’est pi, en une définition

pi est un harness d’agent de codage développé par earendil-works. Il tourne dans le terminal, et c’est ce qui change tout : pas de verrouillage à un éditeur, pas d’UI opaque, tout est scriptable et pilotable par fichiers de config.

Le mot clé, c’est model-agnostic. pi ne vous force pas vers un fournisseur unique. Via un simple models.json, on branche OpenAI, Anthropic, Google AI Studio, ou des backends locaux comme Ollama ou vLLM. Hier je codais avec un modèle cloud, aujourd’hui je teste un llama3.1 local pour une tâche isolée — même harness, zéro friction.

L’installation tient en une ligne :

Terminal window
npm i -g @earendil-works/pi-coding-agent

Détails et sources : le repo GitHub et le paquet npm.

Les skills : des capacités à la demande

Un skill est un package de capacité invoqué à la demande via /skill:name. Pas de code bundlé qui tourne en permanence : c’est un prompt et un process chargés au runtime quand on en a besoin. Ça garde l’agent léger et spécialisable selon le contexte.

Trois skills que j’utilise réellement chaque semaine :

  • /skill:brainstorming — transforme une idée floue en une spec validée. On pose des questions une par une, on propose des approches, on décompose le scope. La règle d’or : pas de code tant que le design n’est pas approuvé.
  • /skill:ponytail — injecte la discipline du « senior dev paresseux » : YAGNI avant tout, un-liner avant une classe, suppression avant addition. C’est un garde-fou contre l’over-engineering que les LLM adorent.
  • /skill:synology-dsm — pilote mon NAS via les bonnes API DSM, sans jamais installer d’outil sur l’appliance. Un skill encapsule toute la connaissance « comment on parle à ce matériel », réutilisable d’une session à l’autre.

La différence skill vs extension est subtile mais importante : un skill est un prompt/process, une extension est un module TypeScript qui enregistre outils, raccourcis et composants UI. Les skills sont la couche haute — ils orchestrent le comportement, les extensions exposent les capacités.

Subagents : l’orchestrateur et ses exécutants

Sous le capot, l’agent est un orchestrateur. Pour le travail non-trivial — feature, bugfix, refactor, multi-fichier — il ne code pas en direct : il délègue à des subagents spécialisés. La règle qui change tout : le skill fournit la méthode, le subagent fournit l’exécutant. Trivial (quelques lignes, pas de changement de comportement) → édition directe. Non-trivial → délégation obligatoire.

Via pi-subagents, une session principale peut fan-out vers des rôles distincts :

  • planner — transforme une spec en plan d’implémentation concret, tâche par tâche.
  • oracle — garde-fou décisionnel : valide qu’on ne dérive pas d’une décision héritée avant de coder.
  • scout / researcher — reconnaissance : un fouille le codebase local, l’autre cherche en ligne. Lancés en parallèle.
  • worker — exécution ciblée. Un seul fil d’écriture, des edits atomiques.
  • reviewer — vérification : critères d’acceptation, build, cohérence.

La délégation suit un routing par étape, où chaque stage marie un skill à un subagent :

  • Comprendre : brainstorming + scout/researcher, avec un recall mémoire en entrée.
  • Isoler : using-git-worktrees — worktree dédié avant d’écrire.
  • Planifier : writing-plans + planner.
  • Implémenter : test-driven-development + worker — un seul fil d’écriture.
  • Revoir : requesting-code-review + reviewer (contexte frais) · oracle (dérive), puis persist mémoire.
  • Valider : verification-before-completion — la session principale joue les checks.

Le skill précède toujours son worker. On parallélise la lecture, la recherche et la revue — jamais l’écriture. Et l’orchestrateur garde l'autorité : les subagents ne décident ni le scope ni l’architecture ; ils exécutent et remontent.


La note honnête : cet article même a été produit par cette chaîne. scout et researcher ont rassemblé les sources sur pi, oracle a tranché le fork d’architecture (FR-only vs bilingue), planner a découpé le plan, et un worker a écrit ces lignes. Cette mise à jour — pour refléter la nouvelle doctrine — a suivi le même chemin : planner → worker → reviewer. La session principale n’a fait qu’orchestrer.

agentmemory : la mémoire qui survit à la session

Le problème de tout agent : chaque session repart de zéro. On ré-explique les conventions, on redemande les préférences, on répète les leçons déjà apprises. C’est l’effet « poisson rouge » des LLM.

agentmemory corrige ça. C’est un store cross-session qui tourne sur http://localhost:3111. Trois mécanismes :

  • un recall auto-injecté à chaque tour — l’agent récupère le contexte pertinent sans qu’on le demande ;
  • memory_search pour un rappel ciblé en profondeur sur un sujet précis ;
  • memory_save pour persister un fait durable : convention adoptée, préférence utilisateur, bug confirmé et son fix.

Ces appels s’alignent sur l’orchestration : recall à l’entrée d’une étape (avant de décider), persist à la revue (après qu’un fix ou une décision est confirmée). La session principale possède tous les appels mémoire — les subagents remontent des candidats, ils n’écrivent jamais directement.

Cas concret : mes préférences de commit (conventional commits, scope entre parenthèses), les conventions de mes projets, un bug n8n déjà résolu sur le NAS — tout ça est rappelé sans que j’aie à re-spécifier. Le rappel est là, silencieusement, au moment de décider.

Une discipline rigide accompagne l’usage : agentmemory ne stocke que le durable. Pas de notes de scratch éphémères, pas d’état transitoire. Et surtout, jamais de secrets — pas de tokens, pas d’auth.json, pas de mots de passe. Si le serveur mémoire tombe (status 🧠 agentmemory off), on appelle memory_health avant de conclure que la mémoire est vide.

Config pilotée par dotfiles : la source de vérité

pi se configure comme un bon outil Unix : via des fichiers, versionnés, dans mes dotfiles. ~/dotfiles est la source de vérité ; les liens symboliques sont propagés vers ~ via GNU Stow (stow -t ~ <pkg>), jamais avec un ln -sf manuel. Éditer la cible d’un symlink, c’est casser la propagation au prochain restow.

La configuration de l’agent suit une découverte hiérarchique :

  • Global : ~/.pi/agent/settings.json, models.json, trust.json.
  • Projet : .pi/settings.json surcharge le global.
  • Contexte : les fichiers AGENTS.md sont chargés depuis ~/.pi/agent/AGENTS.md et remontent l’arborescence depuis le projet (<projet>/AGENTS.md, puis parents). C’est le mécanisme walk-up : chaque projet peut avoir ses règles sans polluer le global.

Trois directives cadrent tout le comportement de mon agent, écrites directement dans AGENTS.md :

  • SUBAGENTS — l’agent est un orchestrateur. Travail trivial → édition directe. Travail non-trivial → délégation obligatoire aux subagents. Le skill donne la méthode, le subagent donne l’exécutant. Un seul fil d’écriture ; l’orchestrateur garde l’autorité sur le scope et l’architecture.
  • AGENTMEMORYrecall à l’entrée, persist à la revue. Durable seulement, jamais de secrets. La session principale possède tous les appels.
  • DOTFILES — éditer ~/dotfiles/<pkg>, jamais le lien résolu. Utiliser stow.

Le ton d’une directive est direct, presque impératif — un extrait :

## Code principles to apply
- SOLID: One class, one job. Add new, no change old.
- YAGNI: Build what need now.
- Never edit the symlink target. Use `stow`.

Ce qui rend pi puissant à long terme, c’est que toute cette configuration est reproductible. Nouveau poste ? git clone des dotfiles, un stow, et l’agent retrouve ses marques — ses skills, ses directives, sa mémoire.

pi vs Cursor / Claude Code / Aider

Comparaison sur ce qui compte pour un usage CLI et automatisable. Le tableau parle de lui-même :

CritèrepiCursorClaude CodeAider
CLI-native (IDE)
Model-agnosticPartiel (Anthropic)
Skills à la demande
Subagents / délégation (ext.)Partiel
Mémoire cross-session
Config pilotée par dotfilesPartiel

« ext. » signifie via pi-subagents — c’est extensible, pas monolithique. pi n’est pas le plus simple à prendre en main, mais c’est le seul qui coche toutes les cases pour un usage avancé et scriptable.

Ce que je ferais différemment

Pas un panégyrique — voici les limites réelles, pour être honnête :

  • Courbe d’apprentissage réelle. La configuration n’est pas triviale : models.json, les directives, les skills, les subagents. pi n’est pas plug-and-play. C’est un investissement initial qui ne se rentabilise que si on code quotidiennement avec. Pour un usage ponctuel, Cursor gagne sur la simplicité.
  • Documentation parfois clairsemée hors du repo. Beaucoup de comportements ne sont documentés que dans la source elle-même. Quand un skill ne se charge pas comme prévu, il faut lire le code plutôt qu’un manuel. Acceptable pour un utilisateur technique, frustrant sinon.
  • Tendance à sur-déléguer. La chaîne de subagents est élégante, mais lourde pour les tâches triviales. Un un-liner bash vaut souvent mieux qu’un fan-out planner → worker → reviewer. La discipline du lazy senior s’applique aussi à l’orchestration : le premier barreau qui tient est le bon.
  • Subagents et MCP non natifs au base harness. Ces capacités reposent sur des extensions tierces (pi-subagents). Ça marche, mais ça ajoute une dépendance et une surface de maintenance. À peser.

Aller plus loin

pi n’est pas un chatbot qu’on interroge ; c’est un harness qu’on configure comme un atelier. L’investissement initial est réel, mais les rendements sont compounding : chaque skill écrit, chaque fait persisté en mémoire, chaque directive dans les dotfiles se réutilise indéfiniment. Au bout de quelques mois, l’agent connaît mes conventions mieux que moi-même.

Pour creuser :

Et pour concrétiser le « model-agnostic », un backend local via models.json — ici Ollama avec une clé récupérée depuis le trousseau macOS :

{
"providers": {
"ollama": {
"baseUrl": "http://localhost:11434/v1",
"apiKey": "!security find-generic-password -ws 'Ollama'",
"models": [{ "id": "llama3.1:8b" }]
}
}
}

La même base de code, le même harness, un modèle local. C’est ça, l’agnosticisme réel.

Table des matières

My avatar

Merci d’avoir lu cet article ! N’hésitez pas à consulter mes autres publications ou à me contacter via les liens sociaux en bas de page.

Commentaires