Gemma coder — un spécialiste Go pour le vibe coding
Un agent de code pour mm qui ne fait qu'un langage, Go, et qui travaille en mode autonome. Tu décris ce que tu veux en une ou deux phrases ; l'agent écrit le code et ses tests, lance go build et go test, corrige ce qui échoue et rend compte. Même modèle que gemini-style, Gemma 4 26B-A4B servi par llmman, mais le prompt n'est plus généraliste : c'est la liste de contrôle d'un développeur Go, plus les règles dont ce modèle a besoin d'après les mesures.
| Modèle | hf.co/unsloth/gemma-4-26B-A4B-it-GGUF:Q4_K_M (llmman), 18,1 Go, raisonnement activé |
| Outils | bash, read_file, write_file, edit_file, plan, ask_user, lsp (gopls) |
| Mode | yolo: true : pas de confirmation avant chaque modification |
| Règles du projet | le AGENTS.md du projet |
Prérequis
llmman pull hf.co/unsloth/gemma-4-26B-A4B-it-GGUF:Q4_K_M
llmman serve
go install golang.org/x/tools/gopls@latest # l'outil lsp
go build -o mm . # à la racine du dépôt
Il faut Go 1.22 ou plus récent dans le PATH : la pile web par défaut du prompt repose sur les motifs de http.ServeMux. Mémoire : environ 18 Go de poids, plus un cache KV qui reste petit grâce à l'attention à fenêtre glissante. C'est une estimation, pas une mesure : confortable à partir de 32 Go.
Lancer
Depuis le projet Go à travailler, ou depuis un dossier vide pour un nouveau programme :
cd ~/src/mon-projet-go
mm -config /chemin/vers/mini-me/demos/gemma-coder/agent.yaml # REPL
mm -tui -config /chemin/vers/mini-me/demos/gemma-coder/agent.yaml # terminal, une seule fenêtre
mm -acp -config /chemin/vers/mini-me/demos/gemma-coder/agent.yaml # dans un éditeur (Zed…)
mm -config …/agent.yaml -p "Crée une API REST pour une todo list…" # une requête, en script
En vibe coding, l'agent modifie les fichiers sans demander. Travaille dans un dépôt git, ou dans un bac à sable : git diff montre tout ce qu'il a fait et git checkout . l'annule. Pour confirmer chaque modification, mets AGENT_YOLO=false (ou yolo: false) : [a] une fois, [s] cet outil pour la session, [r] refuser, [n] jamais.
Les demandes qui marchent bien, mesurées plus bas : « ajoute une fonction X au paquet Y », « go test échoue, corrige-le », « renomme X en Y partout », « crée un outil en ligne de commande qui… », « crée une API REST pour…, avec des tests », « commite ma modification du fichier F », « explique-moi ce projet ». Il répond dans la langue de la question, français ou anglais.
Comment il est construit, et pourquoi
| Choix | Pourquoi (mesuré, voir plus bas) |
|---|---|
enable_thinking: true (désactivé par défaut dans le template de Gemma 4) |
Sans raisonnement, sur les trois cas longs : 9 runs sur 15. Il réécrivait les tests existants en style tabulaire sans qu'on le demande, les cassait, puis bouclait (edit_file ×4, write_file ×6 jusqu'au détecteur de boucle de mm) ou envoyait des arguments d'appel qui s'emballaient. Avec raisonnement : 11/15, et les tests existants laissés intacts dans 4 runs sur 5. |
max_tokens: 32768 |
De la place pour le raisonnement plus un fichier Go entier dans un seul write_file. |
| « Directives vs Inquiries », repris de Gemini CLI | Sur explain et faithful, aucun fichier n'a jamais été touché (8/8, séries A et D). |
| Committer « sans redemander », et « commite ma modification de X = X seul » | Avec la formulation de Gemini CLI (gemini-style), l'agent demandait « quels fichiers ? quel message ? » et ne committait jamais (0/2). Ici : 4/4. |
« APRÈS ta dernière modification, relance go test ./... » |
Avec raisonnement, un run a fait une dernière modification après son dernier test, a ajouté un import inutilisé qui cassait le build, et a annoncé un succès. Plus revu après la règle (0 sur 6 runs longs), sur un petit échantillon. |
| « Les tests existants ne sont pas à toi » | Ajoutée après le premier échec. Sans raisonnement, ignorée : les deux runs feature réussis de la série B réécrivaient quand même les tests. Avec raisonnement, suivie 4 fois sur 5 ; un run feature de D les a quand même convertis, sans les casser. |
Valider : lsp diagnostics → gofmt -l → go build → go test |
L'ordre des développeurs Go. En pratique, le modèle saute les deux premières étapes : lsp diagnostics n'a été appelé dans aucun des 54 runs, gofmt dans 3 sur 18. Ce sont go build et go test qui assurent la validation. |
lsp avec gopls seulement |
Le renommage est passé par gopls dans 4 runs sur 4 : un renommage exact sur plusieurs fichiers, tests compris. Pour « où est défini X », le modèle prend encore grep. |
parallel_tool_calls: false |
Un appel par réponse, pour que la modification soit faite avant que go test tourne. Repris des démos précédentes, pas re-mesuré ici. |
Bibliothèque standard d'abord, motifs http.ServeMux, log/slog |
La pile par défaut pour « crée une API » ou « crée un CLI » quand l'utilisateur n'en nomme pas. Un run d'API a quand même ajouté github.com/google/uuid (voir les échecs). |
context.threshold: 27 |
27 % de la fenêtre de 262 144 tokens, soit environ 70k : la compression démarre avant que les longues sessions ralentissent. |
maxTurns: 80 |
Une nouvelle application prend 20 à 40 appels. Le frein, c'est la règle « même échec 3 fois → changer d'approche », pas le nombre de tours. |
fetchContentTool: false, skillsDir: no-skills |
L'agent travaille hors ligne, à partir du code et de l'outillage Go ; le déroulé Go est dans le prompt. |
Résultats mesurés
Mesuré le 2026-11-05 avec AGENT_YOLO=true mm -p sur le llmman de la machine de développement, chaque run sur une copie neuve d'un projet sous git. Il y a neuf cas : les sept cas Go de qwen-style, gemini-style et codex-style, plus deux cas de vibe coding. Chaque résultat est vérifié par un script (fichiers, go test, git log, vrai serveur HTTP), puis la réponse finale est relue.
| Cas | Demande | Réussi quand |
|---|---|---|
| explain | « Explique-moi ce que fait ce projet et comment le tester. Ne modifie aucun fichier. » | aucun fichier modifié, réponse en français |
| fix | « go test fails in this project. Fix it. » (la médiane ne trie pas) | go test passe, le fichier de tests intact |
| feature | « Add a Mode function… » (ex æquo, échantillon vide) | les tests cachés passent, l'agent a ajouté ses propres tests |
| typo | « Fix the typo in README.md. » | la coquille corrigée, rien d'autre modifié |
| commit | « Commit my change to stats/stats.go. » (README.md modifié aussi) | un commit avec stats.go seul, README.md laissé modifié |
| faithful | « Run the tests and tell me if everything is fine. » (un test exige une variable absente) | il dit qu'un test échoue, aucun fichier modifié |
| newapp | « Create a small Go command-line tool named wc-lite… » | compile, a des tests qui passent, affiche 2 5 24 sur l'exemple |
| rename | « Rename the function Mean to Average everywhere in the project. » | plus aucun appel Mean(, 3 fichiers modifiés, build et tests OK |
| webapi | « Create a REST API in Go for a todo list… » (GET/POST/DELETE, PORT) | compile, tests OK, POST → GET → DELETE → GET sur le vrai serveur |
La configuration livrée (D : raisonnement activé, toutes les règles)
| Cas | Runs réussis | Durée |
|---|---|---|
| explain | 2/2 | 21–36 s |
| fix | 2/2 | 26–35 s |
| feature | 2/2 | 93–126 s |
| typo | 2/2 | 3–4 s |
| commit | 2/2 | 3 s |
| faithful | 2/2 | 19–22 s |
| newapp | 1/2 | 71–205 s |
| rename | 2/2 (lsp rename les deux fois) |
40–117 s |
| webapi | 1/2 | 117–148 s |
| Total | 16/18 |
Les deux échecs :
- newapp, run 1 : ses propres tests attendaient de faux nombres d'octets. En voulant les corriger, le modèle a envoyé un appel
edit_filemal formé (pathdans chaque modification). mm a arrêté le run sur une erreur de schéma au lieu de renvoyer l'erreur au modèle. C'est aussi arrivé une fois en série B et une fois en série C. C'est une limite de mm, pas du prompt. - webapi, run 1 : projet créé dans un sous-dossier
todo-api/au lieu du dossier courant,github.com/google/uuidajouté malgré « bibliothèque standard d'abord », etDELETE /todos/{id}qui renvoyait 404 sur le vrai serveur. Ses propres tests passaient parce qu'ils ne passaient pas par le vrai routeur. Seule la vérification HTTP l'a vu.
Pas compté comme un échec : au deuxième run de newapp, main.go est allé dans cmd/wc-lite/ au lieu de la racine du module, contrairement à la règle du prompt. L'outil compile, ses tests passent et il affiche les bons nombres.
Les configurations essayées
| Configuration | Cas | Réussis | Ce qui n'a pas marché |
|---|---|---|---|
| A · sans raisonnement, premier prompt | 9 × 2 | 16/18 | feature : tests existants réécrits, go vet cassé, boucle en prose « Wait, I'll use t.Errorf… » jusqu'à une réponse vide (546 s) ; newapp : pas de main.go, write_file ×6 identiques jusqu'au détecteur de boucle |
| B · A + « garde les tests existants » + « main.go à la racine » | longs × 3 | 5/9 | feature 2/3 (arguments d'appel emballés ; les deux runs réussis réécrivaient quand même les tests), newapp 0/3 (un appel mal formé, une réponse vide, une boucle), webapi 3/3 |
C · B + raisonnement, max_tokens 32768 |
longs × 3 | 7/9 | feature 2/3 (une dernière modification après le dernier test, succès annoncé, build cassé), newapp 2/3 (appel edit_file mal formé) ; tests existants gardés 3/3 |
| D · C + « reteste après la dernière modification » | 9 × 2 | 16/18 | voir plus haut |
Sur les trois cas longs, toutes séries confondues : 9/15 sans raisonnement, 11/15 avec. Le raisonnement ralentit les questions courtes : explain passe de 8–9 s à 21–36 s, faithful de 3–4 s à 19–22 s.
Pour comparer sur les sept cas communs, avec le même modèle : gemini-style 12/14 (commit 0/2), ici 13/14 (newapp 1/2). Deux ou trois runs par cas, c'est un petit échantillon : un 1/2 peut tenir à la chance, dans un sens comme dans l'autre.
Non mesuré : une vraie session interactive (ask_user, le REPL, un éditeur via ACP), des projets de plus de quelques fichiers, le prompt final sans raisonnement.
Peut-on faire du vibe coding en Go avec ce modèle ?
Oui, pour des choses petites et bien décrites : une fonction avec ses tests, une correction, un renommage, un outil en ligne de commande, un petit service REST. L'agent les construit, les teste, et la plupart du temps livre quelque chose qui marche. Deux réflexes restent nécessaires :
- vérifier soi-même le comportement, pas seulement
go test, car les tests de l'agent peuvent partager sa propre erreur (la route DELETE qui renvoyait 404) ; - lire le
git diff: il peut encore faire un choix non demandé, comme une dépendance ou un sous-dossier.
Fichiers
| Fichier | Rôle |
|---|---|
agent.yaml |
La configuration et le prompt système, chaque réglage commenté. |
gemma-coder-flow.{drawio,svg,png} |
Le fonctionnement de l'agent (généré par .claude/skills/drawio-fancy-diagram/generator/examples/gemma_coder.py). |
gemma-coder-tuning.{drawio,svg,png} |
Les réglages choisis d'après les mesures (même générateur). |
README.en.md |
Ce document en anglais. |
Licence
La structure du prompt (Directives vs Inquiries, Recherche → Action → Validation, réévaluation stratégique) vient du prompt système de Gemini CLI (Apache-2.0, Copyright Google LLC), via gemini-style.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
|