todo (core)
Le dépôt est une machine à états en boucle fermée construite à partir de fichiers qui existent déjà. Rien d'autre ne stocke l'état.
| Couche | Fichier(s) | Rôle | Politique d'écriture |
|---|---|---|---|
| Exigences | README.md, docs/*.md | Vérité fondamentale : contrats, spécifications, configuration, plans longs | Principalement en lecture. Édité sous "Dérive de documentation" dans todo-continue ; les documents de plan (docs/plans/) par todo-init/todo-plan/todo-add/todo-update ; la ligne Tests: du README par todo-init sur un oui ; le RTM optionnel (reference/rtm.md) par todo-plan/todo-add/todo-continue uniquement s'il existe déjà ; docs/status.html par todo-report |
| File active | TODO.md | Un arbre de tâches. Un suivi des éléments de travail, pas un lieu de conception | Édité uniquement par les compétences todo-* |
| Validation | Code source + suites de tests | Vérité fondamentale pour "terminé" | Modifié uniquement pour la tâche en cours |
| Archive | CHANGELOG.md | Permanent, ajout seulement (Keep a Changelog + Conventional Commits) | Seule la section ## [Unreleased] (lors de la publication : renommée en version, une nouvelle section vide au-dessus, et les lignes de lien à la fin) est touchée, par un drain racine et le /todo-release confirmé ; todo-init crée le fichier ou ajoute une section [Unreleased] manquante |
| Vérifications (optionnel) | .todo/check.sh, .todo/todo-lint.sh, tâche CI | Lint + tests, exécutés par CI, un hook pre-push et /todo-continue | check.sh écrit par /todo-init --ci sur un oui ; todo-lint.sh copié par l'utilisateur ; commité par l'utilisateur |
| Stockage de version | git | Branche ou arbre de travail par tâche. Rien n'atteint la branche de base sans vérification | Voir "Mode Git" |
Privilégiez les outils natifs de fichiers (Lire/Éditer/Écrire) pour les modifications de fichiers ; quelle que soit la méthode d'édition, modifiez uniquement les lignes prévues et conservez le saut de ligne final du fichier. Utilisez le shell uniquement pour git, les commandes de test et Done when, les scripts optionnels, et les commandes de fichiers nommées par une compétence (cp, chmod, mkdir -p, date, grep, cmp, mv, et rm de son propre fichier temporaire).
Les fichiers du backlog sont TODO.md, CHANGELOG.md, docs/plans/PROJECT.md, docs/plans/<ID-RACINE>-*.md nommés par une Ref:, et les lignes Tests: et Base: du README écrites par une compétence todo-*. README.md est stagé par un commit de backlog uniquement lorsque git diff README.md ajoute exactement ces lignes, éventuellement après une ligne vide ; les modifications du README effectuées par un nœud sous "Dérive de documentation" sont les fichiers de ce nœud et sont commitées avec lui ; tout autre changement du README appartient à l'utilisateur : il compte pour la vérification de l'arbre propre et n'est jamais stagé par un commit de backlog. Les modifications du backlog restent non commitées jusqu'au prochain commit effectué par une compétence sur une branche todo/ (la revendication d'arbre, généralement), qui les stage par chemin explicite. Les nouvelles racines, et toute modification d'un nœud d'un arbre non revendiqué, sont effectuées uniquement sur la branche de base ; sur une branche todo/ les compétences les refusent et nomment la base. La vérification de l'arbre propre (reference/git-flow.md) les ignore.
Utilisation directe
/todo seul est en lecture seule : liste les commandes, exécute la vérification des invariants sur TODO.md s'il existe, signale. Ne rien modifier.
| Commande | Objectif |
|---|---|
/todo-init | Amorcer les fichiers, détecter la commande de test et git, pré-planification optionnelle et configuration CI, migrer l'ancien format |
/todo-plan | Planifier le travail en files et un arbre ; réviser le plan à tout moment |
/todo-add | Ajouter une tâche, ou décomposer une demande en un arbre |
/todo-continue | Exécuter le prochain nœud de tâche, le vérifier, le fusionner dans son parent |
/todo-update | Modifications manuelles de l'état et des champs |
/todo-status | Arbre, files, historique et recherche en lecture seule |
/todo-report | Écrire une page HTML de statut interactive dans docs/status.html |
/todo-release | Transformer [Unreleased] en une version après confirmation de l'utilisateur |
Chaque compétence exécute uniquement sa propre commande et ne s'enchaîne jamais dans une autre sans y être invitée.
Mode Git
Au début de chaque commande, exécutez git rev-parse --is-inside-work-tree.
- Dépôt Git : chaque nœud travaille sur sa propre branche ou son propre arbre de travail (
reference/git-flow.md). La branche de base est celle nommée par l'utilisateur, sinon la ligneBase:du README, sinon la première qui existe parmimain,master,trunk,develop; si aucune, demandez une fois. Lorsque l'utilisateur nomme une base différente de cette valeur par défaut, proposez d'ajouterBase: <branche>au README (écrit sur un oui ; un fichier de backlog comme la ligneTests:). Chaque étape qui extrait (checkout) ou fusionne dans la base (revendication d'arbre, libération de revendication, fusion de base, publication) s'exécute dans le checkout principal (la première entrée degit worktree list) : depuis un arbre de travail lié,cdd'abord ; s'il est sur une autre branche avec des modifications, arrêtez-vous et imprimez les commandes. - Pas un dépôt Git : avertissez une fois par commande : "Ce n'est pas un dépôt git. Les compétences todo fonctionnent toujours, mais sans branches, arbres de travail, commits ou fusions, il n'y a donc ni isolation ni historique. Exécutez
git initpour les activer." Utilisez ensuite le mode sans git : sautez chaque étape git, suivez la progression dansState:(y comprisfiles:touchés), mettez toujours à jour les marqueurs et drainez vers CHANGELOG.md. La vérification reste inchangée.
Ne jamais tagger, forcer le push, faire un reset hard ou un clean. La seule suppression de branche forcée est celle d'une branche ne contenant que le propre commit de revendication non publié de la compétence (reference/git-flow.md, étapes 2 et 5 de la revendication d'arbre). Les propres commandes git des compétences ne touchent jamais le réseau : pas de fetch, pull ou push. Le partage des commits est le travail de git et le vôtre. Une commande de test peut télécharger des dépendances ; si elle échoue par manque de réseau, bloquez avec cette raison au lieu de réessayer.
Schéma TODO.md
# Active Backlog
## 🌳 Task Tree
Exactement cet en-tête et une section. Pas de sections En Cours, Prêt ou Bloqué : le marqueur sur chaque tâche est son état. Un arbre vide correspond aux deux en-têtes et aucune tâche.
Une tâche fait 2 à 4 lignes : quoi faire, comment elle est validée, liens optionnels et état.
- [ ] **FEAT-002** · P1 · mid · XL · Ajouter le rafraîchissement du token au service d'auth
- Done when: ancien token rejeté après rafraîchissement ; `npx jest tests/auth` ; régression : `npm test`
- Links: Ref: docs/auth.md#refresh · Depends: TASK-001 · From: FIX-001
- State: branch todo/FEAT-002-ajouter-rafraichissement-token-auth depuis main ; next: build children
- [ ] **FEAT-002.1** · mid · Point de terminaison de rafraîchissement
- Done when: point de terminaison couvert par un test d'intégration ; `npx jest tests/auth/refresh.test.ts`
- [/] **FEAT-002.1.1** · high · Interface du magasin de tokens
- Done when: le magasin fait un round-trip d'un token ; `npx jest tests/auth/store.test.ts`
- State: tentatives 1/3 ; baseline 42 passing ; branch todo/FEAT-002.1.1-interface-magasin-tokens depuis todo/FEAT-002.1-point-terminaison-rafraichissement ; next: build
| Partie | Règle |
|---|---|
| En-tête | - [m] **ID** · [P0-P2, racines uniquement ·] COMPLEXITÉ [· TAILLE] · quoi faire, une phrase : complexité low, mid ou high (obligatoire) ; taille S, M, L ou XL (optionnelle) |
Done when: | Obligatoire. Critères, puis ; et au moins une commande exacte entre backticks. Optionnel ; regression: \cmd`` ; sans cela la régression est la suite complète du projet |
Links: | Optionnel. Ref: <chemin#ancre>, Depends: <IDs>, From: <ID>, Lane: <nom> (racines uniquement), séparés par · |
State: | Optionnel, survit à une réinitialisation de contexte. Éléments séparés par ; , chacun au plus une fois, dans cet ordre : attempts n/3, baseline <n> passing (ou none, ou red: <ids de tests en échec, séparés par des virgules>), `tier: <low |
Blocked: | Sur les tâches [!], à la place de State et à sa position (la dernière ligne de champ) : <raison> → <commande entre backticks> <erreur, au plus 5 lignes jointes avec " / "> → <action requise>. Un blocage manuel écrit n/a (manual) au milieu |
Seuls ces quatre champs existent ; une tâche n'a jamais à la fois State et Blocked. Plus de 4 lignes est de la prose de conception et appartient à docs/ (liez-la avec Ref:). Si une tâche a besoin de plus, divisez-la.
Marqueurs : [ ] ouvert, [/] actif (au plus un dans le fichier), [!] bloqué, [x] vérifié et fusionné (ou en cours de fusion) dans son parent, en attendant que sa racine draine.
Arbre, niveaux et complexité
Un nœud au niveau L a son en-tête indenté de 2L espaces et ses champs de 2L+2. Maximum 3 niveaux.
Règle de périmètre. Chaque feuille est un changement qui tient dans une fenêtre de contexte et touche au plus 5 fichiers ; un travail plus volumineux est divisé en enfants (/todo-add). Un nœud trop gros pour être divisé pour l'instant conserve State: next: decompose jusqu'à ce que /todo-continue le décompose.
Taille (optionnelle, après la complexité) enregistre le périmètre quand cela aide un lecteur ; lorsqu'elle est présente, elle doit correspondre à l'arbre, et l'ajout ou la suppression d'un nœud met à jour la taille de chaque ancêtre :
| Taille | Signification | Où |
|---|---|---|
S | Un changement, au plus 2 fichiers | Feuille |
M | Une fenêtre de contexte, au plus 5 fichiers | Feuille |
L | A des enfants, toutes des feuilles | Parent |
XL | A des petits-enfants | Parent |
Une feuille avec State: next: decompose peut porter L/XL.
Complexité indique la difficulté du raisonnement, pas la taille du changement, afin qu'un agent puisse choisir un modèle adapté :
| Complexité | Signification | Exemples |
|---|---|---|
low | Mécanique : la cause et le changement sont déjà connus, pas d'investigation | renommer, docs, config, un garde ou une petite fonction dont le correctif est énoncé dans la ligne de tâche |
mid | Travail ordinaire nécessitant une certaine investigation ou conception (le défaut) | un nouveau point de terminaison, un bug dont la cause doit être trouvée |
high | Raisonnement difficile ou risque élevé | concurrence, sécurité, migration de données, spécification floue, conception entre modules, algorithmes délicats |
Un parent est évalué par sa seule étape d'intégration (généralement low ou mid) ; ses enfants portent leurs propres niveaux. Les racines portent la priorité et la file ; les enfants les héritent.
Routage de modèle (optionnel)
Un projet mappe les niveaux aux modèles avec une ligne README, par exemple Models: low=haiku, mid=sonnet, high=opus (tous noms que l'agent comprend). Sans cette ligne, ou sans outil de sous-agent, la complexité n'est qu'un indice et le travail s'exécute dans le modèle actuel. Avec les deux :
/todo-continue --delegateet les exécutions de file donnent à chaque nœud (ou racine de file, à sa complexité la plus élevée) un sous-agent sur le modèle mappé.- Le relecteur s'exécute au niveau du nœud ou supérieur.
- Escalade : après une tentative de vérification échouée, la tentative suivante s'exécute un niveau plus haut (
low→mid→high), enregistré dansState:commetier:. Une étiquettelowerronée coûte une tentative bon marché, pas un nœud bloqué.
IDs
- Racines
<PRÉFIXE>-<NNN>, une séquence globale, 3 chiffres. Les enfants ajoutent.n:FEAT-002.1,FEAT-002.1.2. Les points égalent le niveau. - Les IDs ne sont jamais réutilisés. Le prochain numéro de racine = le plus grand numéro FEAT-/FIX-/TASK- trouvé dans
TODO.md,CHANGELOG.md(y compris les IDs aprèsIncludes:),docs/plans/*.mdet, en mode git, les sujets de commit (git log --all --format=%s, qui nomment les IDs abandonnés), plus 1. Le prochain numéro d'enfant = le plus grand numéro d'enfant sous ce parent trouvé aux mêmes endroits, plus 1.
| Préfixe | Signification | En-tête CHANGELOG | Type de commit |
|---|---|---|---|
FEAT | Nouvelle capacité | ### Added | feat |
FIX | Bug ou régression | ### Fixed | fix |
TASK | Refactor, chore, docs, test, perf, build | ### Changed | celui qui convient |
Les enfants utilisent le préfixe de leur racine.
Quel nœud est le suivant
Un nœud est travaillable quand : il est [ ] ; chaque enfant est [x] ; chaque ID Depends: est satisfait (dans CHANGELOG.md comme ID d'entrée ou après Includes:, également dans git show <base>:CHANGELOG.md en mode git, ou [x] dans TODO.md ; lorsque seul le CHANGELOG de la base le satisfait, /todo-continue fusionne la base dans la branche à partir de laquelle le nœud démarrera avant de le démarrer, étape 3 ; les commandes en lecture seule signalent "attend une fusion de base") ; aucun ancêtre n'est [!] ; et, en mode git, sa racine n'est pas revendiquée par une autre branche. Une racine est revendiquée quand son State: dans le TODO.md de la branche de base (git show <base>:TODO.md) nomme une branche ; son arbre est travaillable uniquement depuis une branche de cette famille (todo/<ID-RACINE>-… ou todo/<ID-RACINE>.…). Un arbre revendiqué et sauté est signalé comme revendiqué par <branche> ; lorsque cette branche existe dans ce clone, ajoutez "si c'est votre travail : git switch <branche> (ou cd vers son arbre de travail) et relancez pour reprendre". Une branche dans ce clone peut appartenir à une autre session, donc elle n'est jamais reprise automatiquement depuis la base. Si les fichiers du backlog contiennent des modifications non commitées sur la base, git switch vers cette branche échoue : dites-le et proposez d'abord git stash push -- <chemins du backlog> et git stash pop de retour sur la base.
Le travail interrompu passe en premier (mode git). Sur une branche d'arbre (toute branche todo/), listez les branches de l'arbre (git branch --list 'todo/<ID-RACINE>-*' 'todo/<ID-RACINE>.*') et lisez le nœud de chacune dans git show <branche>:TODO.md. Un nœud qui est [x] sur une branche pas encore fusionnée dans la branche de son parent (git merge-base --is-ancestor <branche> <branche parente> échoue) s'est arrêté avant sa fusion : terminez cette fusion et ne faites rien d'autre (étape 2 de /todo-continue). Un nœud qui est [/] est repris, le plus profond d'abord. Un nœud qui est [!] sur l'une des branches de l'arbre compte comme [!] partout (pas travaillable ; ses ancêtres attendent), même là où une autre branche le montre encore [ ] ; une branche dont le nœud n'est plus dans le TODO.md de sa branche parente (supprimé) est ignorée ; une branche déjà fusionnée dans la branche de son parent est supprimée avec git branch -d. Sautez ceci sur la branche de base.
Files
Une file est un rail nommé d'arbres racines qu'un seul contexte d'agent travaille seul, dans l'ordre. Lane: <nom> (une lettre minuscule, puis des lettres minuscules, chiffres ou tirets) sur une racine place tout son arbre dans cette file ; les enfants l'héritent et une racine sans file est dans la file main (donc --lane main sélectionne ces racines). Les files sont du contexte, pas des tâches : une file peut contenir une tâche ou plusieurs, les files s'exécutent en parallèle les unes des autres (/todo-continue exécute --lane main par défaut)