
12
crates Rust
4
providers LLM
AGPLv3
licence du cœur
1
cockpit au lieu de 14 outils
Contexte
Un développeur jongle avec une quinzaine d’outils, sans gouvernance de l’IA ni lien entre ce qui a été demandé à l’agent et ce qui part en production.
Le défi
Unifier le cycle de vie dans un seul cockpit, compatible avec n’importe quel LLM, tout en séparant proprement le cœur open source de l’édition entreprise.
- 01IA
Passerelle LLM
Crate `providers` : Claude Code, Codex, OpenRouter et Ollama derrière une même interface, agents définis en Markdown.
- 02Dev
Moteur de workflows
Pipelines en DAG, runtime d’agents, bus d’événements et shell sandboxé dans un workspace Rust en couches.
- 03Dev
Desktop + CLI
App Tauri 2 / React et CLI avec TUI ratatui, packages TypeScript partagés (ui, client tRPC).
- 04Ops
Open-core vérifié
Un script de CI garantit que le code AGPLv3 ne référence jamais l’édition entreprise (SSO, audit, on-premise).
Architecture
Stack
- Rust
- Tauri
- React
- TypeScript
- SQLite
- AOAgents & orchestration
- OpenRouter / Mistral
- Ollama
- GitHub Actions
Résultats
- ✦Base technique reprise et resserrée dans koklo-cli
- ✦Site produit, docs et design system dédiés
Le récit
Les écrans ci-dessous viennent du design system de Koklo (le Storybook), avec des données de démonstration. Les composants sont ensuite copiés dans l’app desktop, qui branche aujourd’hui les écrans Sessions et Transcript sur le runtime Rust via des commandes Tauri.
Comment ça marche
1. Le projet comme point d’entrée

On ouvre un projet, pas un fichier. L’accueil affiche ce qui bouge : sprints actifs, tickets ouverts, agents en cours. Le fil d’activité met sur le même plan une proposition de l’IA, un push, un ticket passé en review et un déploiement en staging. C’est l’idée de départ de Koklo : arrêter de reconstituer l’histoire d’une fonctionnalité à partir de quatre outils.
2. Un workflow en phases, avec des gates humaines

Une demande passe par un preset de workflow. Le moteur en connaît dix : SDD (spec, plan, implement, test, review), BMAD en huit phases, GitHub Spec Kit, bugfix, release, revue seule, audit seul… Chaque phase est tenue par un agent défini en Markdown. À la fin de la phase, le moteur s’arrête et demande une décision. Ici l’architecte a rendu son analyse : je peux valider, demander des changements, ou éditer le fichier avant de reprendre.

L’écran Workflows garde l’historique. Pour chaque exécution, on retrouve les phases, l’agent, le statut et le fichier produit. Le bandeau en bas de la colonne de droite résume la règle : une sortie reste une proposition tant que la phase n’est pas approuvée.
3. Des tickets reliés au code

Le tableau de sprint est classique. Ce qui change, c’est le panneau du ticket : sessions d’IA liées, commits liés, journal d’activité. Côté Rust, ticket-system stocke les tickets dans SQLite et sait rattacher une session à un ticket (link_session).
4. N’importe quel LLM

Les comptes IA se règlent dans les paramètres. Le crate providers met Claude Code, Codex, OpenRouter et Ollama derrière un même trait. Les CLI d’agent réutilisent l’abonnement déjà en place, sans clé. Ollama permet de tout faire tourner en local.
5. La Constellation, encore à l’état de maquette

La vue Constellation est la plus ambitieuse : une carte de l’historique Git où chaque commit est relié à la session d’IA qui l’a proposé et à la décision humaine qui l’a accepté. Elle existe pour l’instant comme maquette HTML. Dans la feuille de route, elle arrive en phase 9.
Sous le capot
Une gate, de la phase à la décision
Le PipelineOrchestrator ne sait pas qui va décider. Il publie un GateRequired sur le bus, puis confie un GateDisplay (phase, tokens, coût) à un GateHandler. Il en existe trois : un qui lit stdin pour la CI, un qui approuve tout pour les benchmarks, et un qui passe par un canal vers la TUI. La décision est écrite en base avant d’être annoncée par GateResolved. Un refus ou une édition met la session en pause, et koklo resume la relance plus tard.
Choisir un provider sans rien configurer
Au premier lancement, rien n’est imposé. La détection prend le premier provider réellement prêt. Le détail qui compte : un Ollama qui tourne mais n’a pas le modèle voulu est ignoré, sinon la première exécution échouerait. Une fois le provider choisi, un FallbackProvider peut en chaîner un second.
/// Returns `true` for errors that justify trying the fallback provider.
pub fn is_fallback_worthy(e: &ProviderError) -> bool {
match e {
ProviderError::CliNotInstalled { .. } => true,
ProviderError::CliSessionExpired { .. } => true,
// Ollama is reachable but the configured model isn't pulled — another
// configured provider may be ready, so try it rather than hard-failing.
ProviderError::OllamaModelNotFound { .. } => true,
ProviderError::PtyUnavailable => true,
ProviderError::RateLimited { .. } => true,
ProviderError::Timeout { .. } => true,
ProviderError::HttpError { status, .. } => *status >= 500,
// EmptyResponse, MissingApiKey, UnknownProvider → don't fallback
_ => false,
}
}La liste des erreurs qui justifient un repli est volontairement courte. Une limite de quota, un délai dépassé, une erreur 5xx ou une CLI absente : on essaie le suivant. Une clé manquante ou une réponse vide : on s’arrête, parce qu’un autre provider masquerait un vrai problème de configuration.
La frontière open-core
Le cœur est sous AGPLv3, l’édition entreprise vit dans un autre dépôt. Un script de CI vérifie qu’aucun fichier Rust ou TOML du cœur ne la référence :
Ce que j’en retiens
- Les gates humaines tiennent dans une seule fonction, et c’est voulu : un seul endroit publie, enregistre et tranche. Le reste du moteur ne sait pas s’il parle à une TUI, à un écran desktop ou à un script.
- Le périmètre était trop large. Cinq dépôts, une app Tauri, trois fronts TypeScript, un design system : chaque avancée sur un axe laissait les autres en retard. J’ai repris le moteur, les providers et les gates dans koklo-cli, un seul binaire, et l’app desktop attendra que ce noyau soit validé.
- Le design system a pris de l’avance sur le produit. C’est utile pour fixer l’intention (la Constellation en est le meilleur exemple), mais une maquette n’est pas une fonctionnalité, et je le note comme tel.
Galerie





Parlons-en. Décrivez votre besoin en quelques lignes, je reviens vers vous sous 48 h.