Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

265 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🧠 Klody Code AI

Un agent de code 100 % local — privé, sécurisé, extensible — qui rivalise avec un agent cloud sur une machine perso.

Pas d'API cloud. Aucune donnée ne quitte la machine. Le cerveau (MLX/Apple Silicon), les outils, la mémoire, le RAG, et les connecteurs (Gmail, web, MCP) tournent en local.

Tests Coverage License AI MCP Commits Apple Silicon

Étude de cas technique · Architecture · Sécurité · Pour les entreprises

Status : v2.1+ stable · 2146 tests · CI à gates (bandit / gitleaks / pip-audit / coverage) · cerveau MLX Qwen3.6-35B-A3B · client et serveur MCP


Pourquoi c'est intéressant

La plupart des agents de code envoient ton code et tes données dans le cloud. Klody fait l'inverse : tout s'exécute sur ta machine. Le défi technique — faire d'un modèle local (plus petit que la frontière) un agent fiable — est résolu par l'orchestration, pas par la force brute : un routeur adaptatif, une boucle ReAct qui va au bout, un sandbox isolé, et une discipline de tests/sécurité de niveau production. Le tout extensible via MCP : Klody consomme des serveurs externes (Gmail, web…) et s'expose comme serveur pour d'autres agents.

🔒 Privé par conception 100 % local. Sandbox fichiers multi-racines, fichiers sensibles bloqués partout, anti-SSRF sur le web, commits signés.
🧭 Orchestration, pas brute force Routeur (easy/medium/hard × 14 types de tâches, F1≈0,85), boucle auto-prolongée, Best-of-N conditionnel, anti-stall.
🔌 Extensible via MCP Client MCP (consomme Gmail, web, n'importe quel serveur) + serveur MCP (Cline/Zed/Continue consomment Klody).
🧰 Complet 69 outils, app desktop (Tauri/React, thème clair/sombre/auto), mémoire long terme, RAG livres, retrieval code-aware.
🖥️ Pilote ton environnement macOS (AppleScript, Spotlight, Raccourcis→HomeKit/Automator, Finder), maison connectée (MQTT : ESP32, Raspberry Pi), automatisation fichiers (renommage, organisation, sauvegarde, synchro).
🔨 Toolsmithing Klody ne se contente pas d'utiliser des outils, il les fabrique : scripts, CLI, APIs FastAPI, serveurs MCP, workflows, pipelines, plugins Klody, interfaces web — chacun livré avec son test.
⚙️ Ops & génération Introspection Docker/Kubernetes/Git (lecture seule, mutations gated), SQL SQLite sandboxé, diagrammes UML, scaffolding d'API REST/GraphQL, SDK et repository NoSQL.
Production-grade 2146 tests, coverage 84,3 %, CI 5 jobs (sécurité + régression + contrat), branch protection + signed commits.

Architecture

flowchart TD
    U([👤 Utilisateur]) --> UI["🖥️ App desktop · Tauri 2 + React 19<br/>thème clair/sombre/auto"]
    UI <-->|WebSocket| API["⚡ FastAPI · :8000"]
    API --> ORCH

    subgraph ORCH["🧭 Adaptive Orchestrator — boucle ReAct"]
        R["Router · easy/medium/hard × 14 task_types"]
        L["Boucle auto-prolongée + anti-stall + Best-of-N"]
        R --> L
    end

    ORCH --> TOOLS
    ORCH --> MCPC["🔌 Client MCP"]
    ORCH --> LLM

    subgraph TOOLS["🧰 Outils natifs (69)"]
        direction LR
        T1["fichiers · sandbox<br/>multi-racines"]
        T2["code-aware<br/>tree-sitter + bge-m3"]
        T3["github · preview<br/>audio · skills · mémoire"]
        T4["macOS · MQTT<br/>automatisation · toolsmithing"]
    end

    MCPC -->|outils Gmail| GM["📧 Serveur MCP Gmail · :8084"]
    MCPC -->|outils Web| WB["🌐 Serveur MCP Web · :8085<br/>lecture seule · anti-SSRF"]

    subgraph LLM["🧠 LLM 100% local"]
        direction LR
        B["MLX cerveau<br/>Qwen3.6-35B · :8080"]
        C["MLX code<br/>Qwen3-Coder-30B · :8081"]
        O["Ollama fallback · :11434"]
    end

    TOOLS --> RAG["📚 LibraryBrain RAG · :8765"]
    API -.expose.-> MCPS["📡 Serveur MCP Klody · :8083<br/>(Cline · Zed · Continue le consomment)"]
Loading

Caractéristiques clés

# Feature Détail
1 100 % local & privé MLX sur Apple Silicon (Qwen3.6-35B-A3B cerveau, Qwen3-Coder-30B code). Zéro appel cloud par défaut.
2 Routeur adaptatif classifie chaque prompt → 3 difficultés × 14 task_types (edit, refactor, bug_fix, feature, explain, self_dev, review, test_gen, security, docs, perf, migrate, creative, music) → budget d'itérations + planner + Best-of-N (F1≈0,85).
3 Boucle qui va au bout auto-continue quand la tâche est actionnable ; cliquet de continuation ("ok/vas-y" réutilise le routage).
4 Sandbox isolé multi-racines venv jetable par racine, ALLOWED_ROOTS, exec auto après write (py_compile/pytest).
5 Client MCP consomme n'importe quel serveur MCP ; outils exposés au LLM sous mcp__<srv>__<outil>.
6 Serveurs MCP fournis Gmail (IMAP/SMTP) + Web (fetch/search lecture seule, anti-SSRF) — branchés par une ligne de .env.
7 Serveur MCP Klody Klody = plateforme pour d'autres agents (Cline, Zed, Continue.dev).
8 Retrieval code-aware tree-sitter (symboles/refs) + embeddings bge-m3 (find_symbol, find_relevant_files). Python/JS/TS de base ; Rust/Go/Java/PHP en option (grammaires chargées dynamiquement).
9 Best-of-N + mémoire N candidats T variés + action override ; conventions auto-détectées + mémoire d'erreurs.

Stack technique

Composant Tech
Runtime Python 3.11+ · FastAPI · WebSocket
LLM cerveau MLX-LMunsloth/Qwen3.6-35B-A3B-MLX-8bit (:8080, enable_thinking=false)
LLM code MLX-LMmlx-community/Qwen3-Coder-30B-A3B-Instruct-8bit (:8081)
LLM fallback Ollamaqwen2.5-coder:32b (:11434)
Embeddings Ollamabge-m3
RAG livres LibraryBrain — sqlite-vec + FTS5 (:8765)
MCP FastMCP — Klody client et serveur ; connecteurs Gmail/Web
UI graphique klody-ui — Tauri 2 + React 19 + Tailwind 4 (repo)
Tests pytest2146 tests (+20 skipped) · coverage 84,3 %

Installation

1. Prérequis

pip install mlx-lm              # MLX-LM (Apple Silicon recommandé)
brew install ollama ripgrep     # Ollama (embeddings + fallback), ripgrep (recherche)
pip install sqlite-vec          # optionnel (LibraryBrain)

2. Modèles

# Cerveau MLX (MoE 35B / ~3B actifs, multimodal)
huggingface-cli download unsloth/Qwen3.6-35B-A3B-MLX-8bit
# Spécialiste code (optionnel, port 8081)
huggingface-cli download mlx-community/Qwen3-Coder-30B-A3B-Instruct-8bit
# Embeddings (requis pour le retrieval)
ollama serve && ollama pull bge-m3

3. Cloner et installer

git clone https://github.com/klodynlov/klody-code-ai.git
cd klody-code-ai && python3.11 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env   # puis éditer (voir ci-dessous)

4. Configurer .env (extrait)

BACKEND=mlx
MLX_BASE_URL=http://localhost:8080/v1
MLX_MODEL=unsloth/Qwen3.6-35B-A3B-MLX-8bit
MLX_CHAT_TEMPLATE_ARGS='{"enable_thinking": false}'   # requis pour Qwen3.6 (thinking)

PROJECT_ROOT=/Users/ton-nom/mon-projet                # racine principale du sandbox
# ALLOWED_ROOTS=/Users/ton-nom/Projets:/Users/ton-nom/work   # racines supplémentaires

MAX_ITERATIONS=25                                     # plafond boucle ReAct
# Connecteurs MCP (optionnels) — Klody les découvre au démarrage
# KLODY_MCP_SERVERS={"gmail":"http://127.0.0.1:8084/mcp","web":"http://127.0.0.1:8085/mcp"}

Deux modes, deux conventions. Ci-dessus le mode autonome : deux mlx_lm.server lancés par ce dépôt, adressés par id HF sur :8080/:8081. C'est le bon point de départ pour une première installation.

Derrière le gateway Klody Core (:8090), on référence au contraire des alias (MLX_MODEL=brain) — un id HF figé s'y périme à la première bascule de modèle et renvoie un 404 « modèle inconnu ». Le choix n'est pas cosmétique : start-local-ai.sh lit MLX_MODEL comme un id HF, donc MLX_MODEL=brain le fait échouer, et réciproquement. Tout est détaillé dans README-local-ai.md.

Lancement

./scripts/start-mlx.sh                 # 1. cerveau MLX (~30-60s de chargement)
ollama serve                           # 2. embeddings
python main.py                         # 3. CLI Rich  (--resume / --session <id>)
python api/server.py                   # 4. (option) API WebSocket pour l'UI Tauri
./scripts/start-klody-mcp.sh --http    # 5. (option) exposer Klody en serveur MCP (:8083)

# Connecteurs MCP (option) :
./scripts/start-gmail-mcp.sh --http    # Gmail  (:8084) — voir .env.example
./scripts/start-web-mcp.sh   --http    # Web    (:8085) — lecture seule

Outils disponibles (69 natifs + connecteurs MCP)

Catégorie Outils
Fichiers (multi-racines) read_file, write_file, list_files, search_in_files
Code-aware find_symbol, find_references, find_relevant_files, code_graph, analyze_dependencies, generate_uml (diagramme de classes Mermaid depuis le code)
Exécution execute_command, run_in_sandbox (venv jetable par racine), run_sql (SQLite local sandboxé, lecture seule par défaut)
Ops / runtime docker_control (Docker : ps/images/inspect/logs/stats en lecture seule ; run ultra-contraint si activé), kubectl_control (introspection Kubernetes lecture seule : get, describe, logs, top…), git_control (Git : status, log, diff, show, blame… en lecture seule ; add/commit locaux si GIT_WRITE_ENABLED)
Web preview preview_code (auto-CDN + overlay erreurs JS), preview_file, list_previews
GitHub browse_repo, read_github_file, index_github_repo, clone_github_repo, extract_best_practices, create_project
Audio analyze_audio, edit_wav, mix_stems, generate_silence, convert_format, get_waveform_data
Génération generate_uml (diagramme de classes Mermaid), scaffold_api (squelette CRUD : REST FastAPI ou GraphQL Strawberry), scaffold_sdk (client Python typé httpx), scaffold_nosql (repository MongoDB pymongo)
Musique — composition (mcp__klodymusic__*) evaluer_tessiture, suggerer_tonalites, harmoniser, suggerer_accords, analyser_progression, reharmoniser, moduler, melodie_vers_midi, generer_basse, harmonies_vocales, idees_chanson, composer_demo
Musique — mixage (mcp__klodymusic__*) recommander_eq, detecter_masquage, analyser_balance_tonale, recommander_compression, recommander_saturation (dérivés des mesures objectives d'audio_analysis : LUFS, spectre, largeur stéréo, crest)
Musique — chant (mcp__klodymusic__*) evaluer_tessiture, analyser_justesse (écart en cents vs gamme), recommander_autotune (gamme/vitesse/force), harmonies_vocales
Musique — sound design (mcp__klodymusic__*) generer_preset_synth (patch synthé agnostique par rôle/caractère), organiser_banque (rangement de samples par catégorie)
Musique — DAW / voix mcp__reaper__* (pistes, FX, bus/sends, MIDI, régions, rendu stems, chaîne vocale, arrangement), mcp__vocalbrain__* (generer_chanson chant voix clonée, generer_instrumental morceau sans voix, entraînement de voix)
🖥️ macOS (Apple Silicon) run_applescript, spotlight_search, run_shortcut (HomeKit/Automator), list_shortcuts, reveal_in_finder
🏠 Maison / IoT mqtt_publish, mqtt_subscribe (ESP32, Raspberry Pi, Home Assistant, pont HomeKit)
🧹 Automatisation batch_rename, organize_directory, backup_directory, sync_directories (sandboxés, dry_run par défaut)
🔨 Toolsmithing scaffold_tool (script, cli, api, mcp_server, workflow, pipeline, klody_plugin, web_interface), list_tool_kinds
RAG / Skills search_books, learn_from_books, get_skills, save_skill, list_skills, delete_skill
Mémoire remember_fact, forget_fact
Connecteurs MCP mcp__gmail__* (8 outils), mcp__web__* (fetch_url, web_search), + tout serveur MCP branché

🔨 Toolsmithing — Klody fabrique ses propres outils

Le module le plus puissant : plutôt que de seulement utiliser des outils, Klody en construit de neufs, prêts à l'emploi et livrés avec leur test.

scaffold_tool(kind="mcp_server", name="capteurs maison", target_dir="~/Projets")
→ capteurs_maison/capteurs_maison_server.py  (serveur MCP FastMCP)
  capteurs_maison/test_capteurs_maison_server.py
  capteurs_maison/requirements.txt + README.md
kind Produit
python_script script CLI autonome (argparse) + test
cli CLI multi-commandes (sous-commandes) + test
api API FastAPI (health + echo) + test TestClient
mcp_server serveur MCP FastMCP branchable dans Klody + test
workflow orchestrateur d'étapes séquentielles + test
pipeline pipeline ETL (extract → transform → load) + test
klody_plugin plugin outil Klody (schéma registry + handler)
web_interface interface web statique autonome (HTML + JS)

Sécurité

  • Sandbox fichiers : accès limité aux racines autorisées (PROJECT_ROOT + ALLOWED_ROOTS) ; ..//symlinks bloqués ; fichiers sensibles refusés partout (.env .key .pem .p12 .pfx .cer .crt .ppk .p8) ; 1 Mo max/écriture.
  • Sandbox exécution : confirmation en TTY ; blocklist pré-confirmation (sudo, rm -rf /, mkfs, exfil SSH/AWS…) ; run_in_sandbox dans un venv jetable isolé.
  • SQL sandboxé (run_sql) : base SQLite confinée aux racines autorisées, lecture seule par défaut (SQL_WRITE_ENABLED) ; authorizer sqlite3 default-deny, ATTACH/VACUUM INTO/load_extension bloqués, verrou SQLITE_LIMIT_ATTACHED=0, anti-DoS (limites + échéance wall-clock), une seule instruction par appel. Contrôles issus d'un threat-model adversarial.
  • Ops en lecture seule (docker_control, kubectl_control, git_control) : introspection uniquement (Docker : ps/images/inspect/logs/stats… ; k8s : get/describe/logs/top… ; Git : status/log/diff/show/blame…), aucune mutation ; subprocess en argv (pas de shell), sous-commandes/verbes hardcodés, entrées (cible, resource, name, namespace, ref, fichier) validées par charset strict — pas d'injection de commande ni de flag (-o jsonpath, --kubeconfig, --output…) ; dépôt Git confiné aux racines autorisées ; sortie plafonnée, timeout borné. Les mutations Git (add/commit, locales et réversibles) sont désactivées par défaut (GIT_WRITE_ENABLED) ; push/pull et les opérations destructives (reset/checkout/clean/rebase) restent hors de l'outil. Le docker run (mutation) est doublement borné — DOCKER_WRITE_ENABLED et une allowlist d'images non vide — et impose un durcissement figé (aucun flag utilisateur : --network none, --cap-drop ALL, no-new-privileges, limites ressources, pas de montage) ; build/exec/rm restent exclus.
  • Web en lecture seule : fetch_url/web_search en GET, http/https only, anti-SSRF (IP privées/loopback/link-local refusées, y compris via redirection), taille plafonnée.
  • Pilotage macOS : garde plateforme (hors macOS → message clair, jamais d'exception) ; blocklist AppleScript (suppression, vidage corbeille, extinction, do shell script, contrôle UI synthétique refusés) ; reveal_in_finder/Spotlight confinés aux racines autorisées ; timeouts + sortie plafonnée.
  • Automatisation & toolsmithing : opérations de masse en dry_run par défaut (montrent le plan avant d'agir) ; fichiers sensibles exclus partout ; destinations confinées aux racines autorisées ; refus d'écraser un dossier existant. MQTT borné (écoute à timeout dur, payload plafonné, broker local par défaut).
  • Secrets : .env gitignoré, jamais hardcodés ni loggés. Commits signés (ED25519), branch protection sur main.
  • CI : bandit (HIGH), gitleaks, pip-audit --strict, gate coverage 80 %, snapshots contrat MCP/OpenAPI. Plus un bench nightly sur runner self-hosted (non-régression vs baseline versionnée), avec sentinelle qui coupe court — et le dit — si aucun runner n'est disponible.

Tests & bench

python -m pytest tests/ -q                         # 2146 passing
BACKEND=mlx python -m bench.run --category easy    # bench reproductible (20 tâches)
BACKEND=mlx python -m bench.router_eval            # précision du routeur (F1 macro)

Le bench n'est pas décoratif : aucune amélioration ne passe sans gain chiffré (principe n°2 de la roadmap). Trois outils l'appliquent :

python -m bench.gate                               # non-régression vs baseline (CI nightly)
python -m bench.run --repeat 3 --label qwen        # 3 passes — sinon la variance noie l'écart
python -m bench.compare -a qwen*.json -b oss*.json # A/B de deux cerveaux sur TES tâches

bench.compare sort les agrégats (succès, latence, débit, tool calls cassés, itérations ReAct), la ventilation par catégorie et les bascules tâche par tâche. Chaque run enregistre sa provenance — dont le modèle réellement servi, résolu derrière l'alias du gateway — donc deux fichiers de résultats ne sont jamais confondables. Détails : bench/README.md.

Commandes CLI

Commande Description
/help Aide
/sessions Liste / charge une session passée
/memory Mémoire courte + souvenirs long terme
/model · /model <id> Modèle actif / change à chaud
/skills Compétences mémorisées
/exit Quitte
python main.py --resume               # reprend la dernière session
python main.py --session <id-court>   # reprend une session précise

Erreurs fréquentes

Symptôme Cause / solution
APIConnectionError (MLX) Lancer ./scripts/start-mlx.sh
Connection refused (Ollama) ollama serve (requis pour les embeddings bge-m3)
model not found (MLX) huggingface-cli download unsloth/Qwen3.6-35B-A3B-MLX-8bit
Le modèle « réfléchit » sans répondre Qwen3.6 est thinkingMLX_CHAT_TEMPLATE_ARGS='{"enable_thinking": false}' dans .env
SandboxViolation Le chemin doit être sous PROJECT_ROOT/ALLOWED_ROOTS (chemins absolus existants)
Outil MCP absent Vérifier KLODY_MCP_SERVERS + serveur lancé, puis redémarrer le backend (config lue au boot)
UI Tauri figée Cmd+Shift+R ; vérifier python api/server.py sur :8000

Documentation

  • 📐 Étude de cas technique — les décisions d'ingénierie (routeur, MCP, sandbox, la saga max_tokens).
  • 🧠 Pile d'inférence locale — gateway vs mode autonome, modèles, réglages non négociables (thinking coupé, pas de draft model sur le MoE).
  • 📊 Banc de mesure — non-régression, A/B de configurations, répétitions, provenance.
  • 🗺️ Roadmap — les 12 étapes livrées et les décisions qui les ont motivées.
  • 🛠️ OPS — exploitation, services permanents (LaunchAgents).
  • 💼 Pour les entreprises — agents IA privés / local-first.

Licence

MIT © 2026 klodynlov

About

Agent IA CLI local — Python + Ollama + qwen2.5-coder:32b

Resources

Security policy

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages