toro-cli
v0.1.0
Published
Le poste de pilotage de votre app, pour votre IA. Tickets, roadmap, features et journal — sur votre machine.
Maintainers
Readme
Toro
Le poste de pilotage des apps développées avec une IA : tickets, roadmap, features, composants et journal. L'interface les montre, l'API les écrit — et c'est la même porte pour les deux, avec la même clé.
Le problème qu'il traite : quand une IA développe, on voit le résultat mais jamais l'état. Ce qui reste, ce qui bloque, pourquoi telle chose est comme ça, et ce qu'elle a fait pendant la dernière heure.
Stack
| | | |---|---| | Front | React 19 + TypeScript + Vite 7 + Tailwind 4 | | API | Worker Cloudflare, TypeScript, aucun framework | | Base | D1 (SQLite) — locale en développement, distante en production | | Hébergement | Cloudflare Workers avec assets statiques |
Un seul processus sert les deux : @cloudflare/vite-plugin fait tourner le
Worker dans le serveur de développement Vite, avec une D1 locale. Il n'y a
donc rien à lancer à côté, et le code exécuté en local est celui qui partira.
Lancer en local
export PATH="$HOME/.local/bin:$PATH"
pnpm install
pnpm run db:local # applique les migrations sur la D1 locale
pnpm dev # http://localhost:5680Au premier lancement, l'écran demande de créer la première clé d'API. Elle s'affiche une seule fois — l'API n'en garde que le SHA-256. C'est la même clé pour l'interface et pour l'IA.
pnpm run check type-vérifie le front et le Worker (tsc -b, trois projets).
Importer le coffre Obsidian
Le script lit ~/Documents/App creator/Projets/ et les dépôts de
~/Documents/Apps Claude/, puis écrit par l'API — il n'y a pas de chemin
d'accès privilégié à la base.
TORO_TOKEN=toro_… node scripts/import-vault.mjs --projet Vibecoded
TORO_TOKEN=toro_… node scripts/import-vault.mjs --toutIl faut désigner ce qu'on importe — sans --projet ni --tout, le script
refuse et liste les projets du coffre. Un import est une écriture : le défaut
« tout le coffre » avait rempli Toro de quatre projets que personne n'avait
demandés.
Il est idempotent : relancé, il met à jour au lieu de dupliquer. Ce qu'il reprend :
| Source | Devient |
|---|---|
| _Index.md § « Le projet en une ligne » | le projet, son résumé, son URL de prod |
| Gestion de projet.md | les tickets, avec leur identifiant d'origine (SOL-11) |
| Features/<F>/<F>.md | la feature : statut, pourquoi, décisions, ce qu'on n'a pas fait |
| CHANGELOG.md | les versions publiées |
| <dépôt>/src/** | les composants réellement exportés, avec leur signature |
Le préfixe des tickets vient du backlog, jamais du nom : le coffre écrit
FRG pour Forge, et des commits citent FRG-3.
L'API
Base : /api/v1. Tout demande Authorization: Bearer <clé>, sauf /health,
/vocab et /setup. Les réponses sont en français, comme le vocabulaire.
Les deux routes qui portent l'essentiel :
# ce qu'on a le droit d'écrire — statuts, types, attentes, et leur sens
curl -s http://localhost:5680/api/v1/vocab
# le briefing complet d'un projet, en un appel
curl -s -H "Authorization: Bearer $TORO_TOKEN" \
http://localhost:5680/api/v1/projects/solde/contextLe briefing rend l'état, les tickets dans l'ordre de priorité, le prochain non bloqué, ce qui attend Benjamin, les features avec leur statut, les dernières versions, le journal, et le vocabulaire. C'est ce qu'une IA lit en début de session au lieu de deviner.
Le reste : projects, tickets, features, components, milestones,
releases, events, keys — en GET/POST/PATCH/DELETE. Plus deux
routes particulières :
POST /tickets/:id/release— la charnière : le ticket quitte le backlog, son texte devient l'entrée de version, la feature liée passeen prodavec le numéro qui l'a livrée. Il n'y a jamais deux copies de « ce qui a été fait ».GET /projects/:id/export.md— le backlog au format du coffre, tags Obsidian et[[liens]]compris. Le pont de retour vers les notes.
Le vocabulaire est contraint
Statuts de ticket à-faire · en-cours · en-test · à-releaser · released ·
abandonné, types tâche · bug · idée · dette, attentes benjamin · décision ·
plus-tard, statuts de feature en cours · en local · en test · à releaser ·
en prod · abandonnée.
Ils sont repris mot pour mot du coffre, et l'API refuse le reste — en
CHECK dans la migration et en validation dans le Worker. C'est ce qui
empêche une IA d'inventer un septième statut au fil des sessions.
Le journal
Chaque écriture par l'API pose un événement, avec le nom de la clé comme auteur. Une clé par outil, donc : « Claude Code », « Cursor »… C'est ce qui permet de lire le chemin et pas seulement le résultat.
Un scan de composants ne journalise pas ses centaines de lignes : le scanner pose un seul événement de synthèse.
Variables d'environnement
Aucune côté application. Les clés vivent en base, hachées. Le script d'import
lit TORO_TOKEN et, éventuellement, TORO_URL (par défaut
http://localhost:5680).
Déployer
Rien n'est déployé à ce jour. Avant le premier déploiement :
npx wrangler d1 create toro # recopier database_id dans wrangler.jsonc
npx wrangler d1 migrations apply toro --remote
pnpm run deployL'API est ouverte en CORS (*) : c'est voulu, une IA qui appelle depuis
ailleurs doit pouvoir le faire. La clé est le seul contrôle d'accès — il n'y
a pas de comptes, et une clé donne tout. À savoir avant de mettre l'instance sur
Internet.
