Il y a moins d’un mois j’ai écrit un post entier pour expliquer comment utiliser trois couches de mémoire avec Claude Code : Linear pour la stratégie, Beads pour la tactique et Tasks pour l’exécution. Une jolie pyramide, bien élégante.
Ben non.
Aujourd’hui je mets Beads à la retraite. Pas par caprice, mais parce que la réalité s’est chargée de démontrer qu’un outil qui te cause plus de problèmes qu’il n’en résout, c’est pas un outil. C’est un boulet.
Ce que Beads apportait
Pour ceux qui n’ont pas lu le post original, Beads était un issue tracker basé sur git. Un plugin pour Claude Code qui stockait les issues dans des fichiers JSONL à l’intérieur de ton repo. L’idée était brillante sur le papier :
- Persistance dans git : les issues vivaient dans
.beads/et se commitaient avec ton code. - Dépendances : un issue pouvait en bloquer un autre.
- Offline : fonctionnait sans connexion.
- Le LLM le voyait directement : pas d’APIs, pas de configuration. L’agent lisait les fichiers et voilà.
La promesse : une couche intermédiaire entre “ce que je veux faire cette semaine” (Linear) et “ce que je fais maintenant” (Tasks). La colle tactique.
Ce qui a foiré
Tout allait bien jusqu’à ce que ça n’aille plus. Et ça a cessé de fonctionner de façons créatives.
Le daemon de l’enfer
Beads fait tourner un daemon en arrière-plan pour gérer la base de données SQLite et synchroniser avec git. Ça paraît raisonnable. En pratique :
DATABASE MISMATCH DETECTED!
This database belongs to a different repository:
Database repo ID: d1f9ca0c
Current repo ID: 01eac8ea
⚠️ CRITICAL: This mismatch can cause beads to incorrectly
delete issues during sync!
Ce message te saute à la figure au démarrage de chaque session. Le daemon plante, la synchro plante, et tu te retrouves avec des issues qui existent dans ton SQLite local mais pas dans git, ou l’inverse. Un état quantique de bugs : tes issues existent et n’existent pas en même temps.
La synchronisation fantôme
bd sync c’est la commande pour synchroniser tes issues avec le remote git. Sauf quand ça marche pas :
→ Pulling from remote...
Error: pulling: git pull failed: exit status 1
remote: Repository not found
fatal: repository 'https://git.frr.dev/frr/wuwei.git/' not found
En fait, beads récupère le remote depuis git, mais si t’as plusieurs remotes (truc courant), il peut choisir le mauvais. Et si ce remote pointe vers un repo qui n’existe pas ou qui a changé de nom, le daemon te crache des erreurs à chaque opération. En silence, tes issues arrêtent de se synchroniser et tu le réalises que quand t’ouvres une autre session et que tout a disparu.
Le coût cognitif
Chaque session avec Claude Code commençait comme ça :
- Claude lit le prompt de beads (injecté via hooks)
- Le daemon essaie de démarrer
- Plante avec une erreur de mismatch
- Claude essaie
bd sync - Plante avec une erreur de remote
- Tu lui dis “ignore ça”
- Maintenant oui, on peut bosser
Six étapes de friction avant de faire quoi que ce soit de productif. Six étapes qui consomment du contexte, du temps et de la patience.
Ce qui a changé
Deux choses ont fait passer Beads de “outil utile avec des bugs” à “overhead inutile” :
1. Tasks a mûri
Quand j’ai écrit le post des trois couches, Tasks était basique. Maintenant il a :
TaskCreateavec des descriptions, activeForm pour les spinners, et des métadonnéesTaskUpdateavec des dépendances (addBlocks,addBlockedBy)TaskListetTaskGetpour l’inspection- Persistance optionnelle entre sessions avec
CLAUDE_CODE_TASK_LIST_ID
Dit clairement : Tasks fait maintenant tout ce que Beads faisait pour le travail intra-session. Et il le fait sans daemon, sans SQLite, sans synchro git, et sans erreurs fantômes.
2. Le CLI de Linear est arrivé
Le MCP de Linear était, en étant généreux, de la merde. Intermittent, lent, et avec un talent spécial pour planter pile quand t’en avais le plus besoin.
L’alternative c’était taper directement sur l’API avec GraphQL. Ce qui marche, oui, jusqu’à ce que t’essaies de mettre des caractères spéciaux dans les descriptions des issues :
| |
Et puis j’ai découvert le linear CLI :
| |
Et créer un issue devient :
| |
Pas d’escaping GraphQL. Pas de daemon. Pas de synchro cassée. J’ai créé 49 issues en moins d’une minute avec un script bash. Avec le MCP de Linear et l’API, ça m’aurait pris une heure et demie de bagarre avec l’échappement des caractères.
La nouvelle pyramide (qui n’est plus une pyramide)
Le modèle à trois couches était joli. Mais la réalité c’est que deux couches suffisent :
| Besoin | Avant | Maintenant |
|---|---|---|
| Vision stratégique | Linear (MCP/API) | Linear (linear CLI) |
| Travail tactique | Beads | Linear (linear CLI) |
| Exécution en session | Tasks | Tasks |
Linear + son CLI couvre la stratégie et la tactique. Tasks couvre l’exécution. Beads ne couvre rien que les deux autres ne fassent mieux.
Avant :
Linear (semaines) → Beads (jours) → Tasks (heures)
Maintenant :
Linear (semaines/jours) → Tasks (heures)
Moins de couches, moins de friction, moins de trucs qui peuvent casser.
Leçon apprise
Ça me rappelle un truc que je dis tout le temps : la complexité inutile, c’est l’ennemi silencieux. Beads résolvait un vrai problème (l’amnésie du LLM entre les sessions), mais il le faisait en ajoutant une couche d’infrastructure qui, sur la durée, générait plus de problèmes qu’elle n’en résolvait.
C’est toujours la même histoire en ingénierie : la bonne solution parfois c’est pas d’ajouter quelque chose, mais de réaliser que ce que t’as déjà s’est suffisamment amélioré pour que t’en aies plus besoin.
Le MCP de Linear c’était de la merde –> le CLI est arrivé. Tasks était basique –> il a mûri. Beads s’est retrouvé au milieu, sans place.
Le rm -rf final
| |
Deux lignes. C’est comme ça qu’on met un outil à la retraite. Pas de cérémonie, pas de drame.
Beads a été utile tant qu’il l’a été. Maintenant il ne l’est plus. Et c’est très bien comme ça.
TL;DR : Je retire Beads de mon flux de travail avec Claude Code. Le CLI de Linear (schpet/linear-cli) gère les issues sans les galères du MCP ni de l’API GraphQL. Tasks a suffisamment mûri pour couvrir le tracking intra-session. Deux couches suffisent : Linear pour la stratégie et la tactique, Tasks pour l’exécution.
Posts précédents sur le sujet :