<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Claude on Zwindler's Reflection</title><link>https://blog.zwindler.fr/tags/claude/</link><description>Recent content in Claude on Zwindler's Reflection</description><generator>Hugo -- gohugo.io</generator><language>fr</language><copyright>Licensed under CC BY-SA 4.0</copyright><lastBuildDate>Tue, 17 Mar 2026 18:00:00 +0100</lastBuildDate><atom:link href="https://blog.zwindler.fr/tags/claude/index.xml" rel="self" type="application/rss+xml"/><item><title>GenAI et développement logiciel, épisode 2 : kubectl-debug-pvc, de l'idée à krew en 2x30 minutes</title><link>https://blog.zwindler.fr/2026/03/16/genai-llm-dev-kubectl-debug-pvc/</link><pubDate>Tue, 17 Mar 2026 18:00:00 +0100</pubDate><guid>https://blog.zwindler.fr/2026/03/16/genai-llm-dev-kubectl-debug-pvc/</guid><description>&lt;img src="https://blog.zwindler.fr/2026/03/kubectl-debug-pvc.webp" alt="Featured image of post GenAI et développement logiciel, épisode 2 : kubectl-debug-pvc, de l'idée à krew en 2x30 minutes" /&gt;&lt;h2 id="précédemment-dans-genai-et-dev"&gt;Précédemment, dans &amp;ldquo;GenAI et dev&amp;rdquo;
&lt;/h2&gt;&lt;p&gt;Dans &lt;a class="link" href="https://blog.zwindler.fr/2026/03/08/genai-llm-dev-podsweeper/" &gt;mon article précédent&lt;/a&gt;, je vous parlais de mon retour d&amp;rsquo;expérience avec PodSweeper, un projet développé avec OpenCode et Claude Opus. Le bilan était nuancé : vitesse brute impressionnante, mais race conditions, gestion d&amp;rsquo;erreur laxiste, et nécessité constante de supervision humaine (entre autres déconvenues).&lt;/p&gt;
&lt;p&gt;Aujourd&amp;rsquo;hui, je vous parle d&amp;rsquo;un deuxième projet, bien plus simple, né d&amp;rsquo;un vrai besoin en production. Et le constat est assez différent.&lt;/p&gt;
&lt;h2 id="lincident-qui-a-tout-déclenché"&gt;L&amp;rsquo;incident qui a tout déclenché
&lt;/h2&gt;&lt;p&gt;Vous connaissez peut-être cette situation : un pod en production, en état de fonctionnement, qui utilise un PVC en &lt;code&gt;ReadWriteOnce&lt;/code&gt;. Vous avez besoin d&amp;rsquo;aller regarder le contenu de ce volume. Bonne pratique de production : le pod en question ne dispose pas de shell (on réduit la surface d&amp;rsquo;attaque). Pas de &lt;code&gt;/bin/sh&lt;/code&gt;, pas de &lt;code&gt;/bin/bash&lt;/code&gt;, rien.&lt;/p&gt;
&lt;p&gt;Pas grave, on a &lt;code&gt;kubectl debug&lt;/code&gt; pour ça, me direz-vous !&lt;/p&gt;
&lt;p&gt;Ok, créons un conteneur éphémère dans le pod et&amp;hellip; ah non. &lt;code&gt;kubectl debug&lt;/code&gt; ne permet pas de monter les volumes du pod dans le conteneur éphémère. Il n&amp;rsquo;expose tout simplement pas l&amp;rsquo;option &lt;code&gt;volumeMounts&lt;/code&gt; pour les conteneurs éphémères.&lt;/p&gt;
&lt;p&gt;On pourrait couper le pod, ce qui permet de monter le PVC RWO dans un autre pod avec un shell, mais on n&amp;rsquo;a pas envie, c&amp;rsquo;est de la prod.&lt;/p&gt;
&lt;p&gt;Mon collègue Maxime (encore lui !) me propose une méthode de contournement. La procédure manuelle, c&amp;rsquo;est :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Créer un conteneur éphémère sur le pod avec &lt;code&gt;kubectl debug&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Construire à la main un patch JSON pour ajouter des &lt;code&gt;volumeMounts&lt;/code&gt; au conteneur éphémère qu&amp;rsquo;on vient de créer&lt;/li&gt;
&lt;li&gt;Dans un autre terminal, se brancher &lt;del&gt;au cul du camion&lt;/del&gt; sur l&amp;rsquo;API de kube en direct avec &lt;code&gt;kubectl proxy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Appliquer le patch via un curl sur l&amp;rsquo;API Kubernetes&lt;/li&gt;
&lt;li&gt;Attendre que le conteneur soit prêt, s&amp;rsquo;attacher au conteneur&lt;/li&gt;
&lt;li&gt;Se dire qu&amp;rsquo;il y avait quand même plus simple comme métier que patcheur de container à coup de curl.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Pour ceux qui pensent que c&amp;rsquo;est jouable, &amp;ldquo;téma la gueule du patch&amp;rdquo; comme disent (disaient ?) les jeunes :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;curl&lt;/span&gt; &lt;span class="err"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8001/api/v1/namespaces/&amp;lt;namespace&amp;gt;/pods/&amp;lt;pod&amp;gt;/ephemeralcontainers \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="err"&gt;-X&lt;/span&gt; &lt;span class="err"&gt;PATCH&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="err"&gt;-H&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;Content-Type:&lt;/span&gt; &lt;span class="err"&gt;application/strategic-merge-patch+json&amp;#39;&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="err"&gt;-d&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;spec&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;ephemeralContainers&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;debugger&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;image&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;ubuntu&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;command&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/bin/sh&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;targetContainerName&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;lt;target-container&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;stdin&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;tty&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;volumeMounts&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;lt;volume-name&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;mountPath&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/debug/&amp;lt;volume-name&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Si vous pensez que c&amp;rsquo;est error prone, vous avez raison. Et si vous pensez que c&amp;rsquo;est pénible à faire sous pression pendant un incident de prod, vous avez encore plus raison.&lt;/p&gt;
&lt;h2 id="side-note"&gt;Side note
&lt;/h2&gt;&lt;p&gt;Les plus aguerri·es d&amp;rsquo;entre vous dans les versions récentes de Kubernetes ont peut être entendu parler du &lt;a class="link" href="https://kep.k8s.io/2590" target="_blank" rel="noopener"
&gt;KEP-2590&lt;/a&gt;, qui introduit un (relativement) nouveau flag &lt;code&gt;--subresource&lt;/code&gt; de &lt;code&gt;kubectl&lt;/code&gt;. En effet, les containers éphémères créés par la commande &lt;code&gt;kubectl debug&lt;/code&gt; ne sont pas des &lt;em&gt;resources&lt;/em&gt; (un pod, un deployment, &amp;hellip;) mais des &lt;em&gt;subresources&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Jusqu&amp;rsquo;à cette version 1.33, il était littéralement impossible de réaliser des opérations sur les subresources avec &lt;code&gt;kubectl&lt;/code&gt;, seulement les resources.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kubernetes v1.33: Octarine&lt;/strong&gt; apporte le support du flag &amp;ndash;subresource, &lt;strong&gt;mais seulement&lt;/strong&gt; pour 3 subresources pour l&amp;rsquo;instant &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;scale&lt;/code&gt; and &lt;code&gt;resize&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://kubernetes.io/blog/2025/04/23/kubernetes-v1-33-release/#subresource-support-in-kubectl" target="_blank" rel="noopener"
&gt;https://kubernetes.io/blog/2025/04/23/kubernetes-v1-33-release/#subresource-support-in-kubectl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://kubernetes.io/docs/reference/kubectl/conventions/#subresources" target="_blank" rel="noopener"
&gt;https://kubernetes.io/docs/reference/kubectl/conventions/#subresources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pas de solution de ce côté-là non plus&amp;hellip;&lt;/p&gt;
&lt;h1 id="le-prompt-de-réunion"&gt;Le prompt de réunion
&lt;/h1&gt;&lt;p&gt;J&amp;rsquo;avais cette idée en tête depuis l&amp;rsquo;incident. Lundi matin, au début d&amp;rsquo;une réunion (pendant que les gens faisaient encore des blagues), j&amp;rsquo;ai lancé OpenCode avec Claude Opus et j&amp;rsquo;ai tapé un prompt qui décrivait :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Le problème : &lt;code&gt;kubectl debug&lt;/code&gt; ne monte pas les volumes PVC s&amp;rsquo;ils sont en RWO&lt;/li&gt;
&lt;li&gt;La procédure manuelle que je faisais à la main (les étapes douloureuses décrites un peu plus haut)&lt;/li&gt;
&lt;li&gt;Ce que je voulais : un outil qui automatise tout ça&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;OpenCode + Opus m&amp;rsquo;ont posé 2 questions (et j&amp;rsquo;ai ajouté une consigne) :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;Quel langage ?&amp;rdquo;&lt;/em&gt; → &lt;strong&gt;Go&lt;/strong&gt; (je persiste)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;CLI seule ou TUI ?&amp;rdquo;&lt;/em&gt; → &lt;strong&gt;Les deux&lt;/strong&gt; (mode non-interactif pour le scripting, TUI pour l&amp;rsquo;usage quotidien)&lt;/li&gt;
&lt;li&gt;Et je lui ai demandé de toujours vérifier à chaque fois qu&amp;rsquo;il estime avoir fini de lancer le linter &lt;code&gt;golangci-lint&lt;/code&gt; (trauma de mon précédent test avec opencode)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Il est parti de lui-même sur l&amp;rsquo;idée d&amp;rsquo;une TUI avec &lt;a class="link" href="https://github.com/charmbracelet/bubbletea" target="_blank" rel="noopener"
&gt;Bubble Tea&lt;/a&gt;. Puis j&amp;rsquo;ai arrêté de regarder &amp;amp; j&amp;rsquo;ai suivi ma réunion.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;~30 minutes plus tard, fin de la réunion&lt;/strong&gt;, j&amp;rsquo;ai regardé le résultat. Le POC était fonctionnel.&lt;/p&gt;
&lt;h2 id="ce-quopus-a-produit-en-30-minutes"&gt;Ce qu&amp;rsquo;Opus a produit en 30 minutes
&lt;/h2&gt;&lt;p&gt;Sans aucune intervention de ma part, le LLM a scaffoldé un projet Go complet :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Structure propre&lt;/strong&gt; : &lt;code&gt;cmd/&lt;/code&gt; pour le CLI Cobra, &lt;code&gt;pkg/k8s/&lt;/code&gt; pour toute l&amp;rsquo;interaction Kubernetes, &lt;code&gt;pkg/tui/&lt;/code&gt; pour la TUI Bubble Tea&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Le coeur du sujet&lt;/strong&gt; : un appel direct à l&amp;rsquo;API Kubernetes pour patcher le subresource &lt;code&gt;ephemeralcontainers&lt;/code&gt; du pod avec un strategic merge patch incluant les &lt;code&gt;volumeMounts&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mode non-interactif&lt;/strong&gt; : &lt;code&gt;-n namespace -p pod -v volume:/mount/path&lt;/code&gt;, prêt pour le scripting&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TUI complète&lt;/strong&gt; : navigation vim-style (&lt;code&gt;j&lt;/code&gt;/&lt;code&gt;k&lt;/code&gt;), filtrage fuzzy (&lt;code&gt;/&lt;/code&gt;), multi-sélection de volumes, spinner de chargement&amp;hellip;&lt;/li&gt;
&lt;li&gt;Makefile avec tout un tas de targets (vet, lint, test, build, install)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ce que je lui ai demandé d&amp;rsquo;ajouter :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Discovery intelligente&lt;/strong&gt; : au lieu de scanner tous les pods de tous les namespaces (lent sur un de mes gros cluster), l&amp;rsquo;outil liste d&amp;rsquo;abord les PVCs cluster-wide (un seul appel API) pour identifier les namespaces pertinents, PUIS les pods dans le namespace sélectionné. On réduit drastiquement le nombre d&amp;rsquo;appels à l&amp;rsquo;API server de kube et la TUI ne montre que les namespaces et pods qui ont des volumes PVC&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Héritage du &lt;code&gt;SecurityContext&lt;/code&gt;&lt;/strong&gt; : le conteneur éphémère copie le &lt;code&gt;securityContext&lt;/code&gt; du conteneur cible, ce qui lui permet de passer les PodSecurity policies (&lt;code&gt;restricted&lt;/code&gt;, &lt;code&gt;baseline&lt;/code&gt;&amp;hellip;). C&amp;rsquo;est un cas que je n&amp;rsquo;avais pas envisagé dans mon prompt initial et qui a planté immédiatement sur un cluster bien configuré.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sans ces petites améliorations le tool était déjà utilisable (sauf pour le cas où vous avez configuré des SecurityContext), mais c&amp;rsquo;est nettement plus confortable à l&amp;rsquo;usage (parce que oui, je l&amp;rsquo;utilise).&lt;/p&gt;
&lt;p&gt;Le code de la mécanique centrale (le patch de l&amp;rsquo;API) fait quelques centaines de lignes de Go propre. Il récupère le pod, construit le patch JSON avec le conteneur éphémère et ses &lt;code&gt;volumeMounts&lt;/code&gt;, l&amp;rsquo;applique via &lt;code&gt;Patch()&lt;/code&gt; sur le subresource, attend que le conteneur soit Running, puis lance &lt;code&gt;kubectl attach&lt;/code&gt;. Rien de sorcier, c&amp;rsquo;est juste ce qu&amp;rsquo;il faut, bien fait du premier coup.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-golang" data-lang="golang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ephemeralContainer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;corev1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EphemeralContainer&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;EphemeralContainerCommon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;corev1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EphemeralContainerCommon&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;containerName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;/bin/sh&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Stdin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TTY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;VolumeMounts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;mounts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SecurityContext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;targetSecurityContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TargetContainerName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;targetContainer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Clientset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CoreV1&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Pods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Namespace&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Patch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PodName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StrategicMergePatchType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;patchBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;metav1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PatchOptions&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;ephemeralcontainers&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="les-itérations-suivantes-30-minutes-ish"&gt;Les itérations suivantes (30 minutes-ish)
&lt;/h2&gt;&lt;p&gt;Une fois le POC validé, j&amp;rsquo;ai enchaîné quelques prompts ciblés. Je lui ai demandé ce qu&amp;rsquo;on pouvait améliorer. Il a proposé (et implémenté) :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;quelques corrections mineures de code qu&amp;rsquo;il avait mal codé (mais non bloquant)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Warnings&lt;/strong&gt; : si le SecurityContext hérité a &lt;code&gt;readOnlyRootFilesystem&lt;/code&gt;, &lt;code&gt;runAsNonRoot&lt;/code&gt;, ou autre mesure de sécurité, l&amp;rsquo;outil prévient l&amp;rsquo;utilisateur avant l&amp;rsquo;attach&lt;/li&gt;
&lt;li&gt;Ajouté une CI complète à base de &lt;code&gt;goreleaser&lt;/code&gt; et de github actions&lt;/li&gt;
&lt;li&gt;Ajouté de la documentation&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="la-cerise-sur-le-macdo--publication-sur-krew"&gt;La cerise sur le Macdo : publication sur Krew
&lt;/h2&gt;&lt;p&gt;Une fois que j&amp;rsquo;avais une version propre, j&amp;rsquo;ai demandé à Opus comment faciliter l&amp;rsquo;installation du plugin. Il m&amp;rsquo;a proposé &lt;code&gt;brew&lt;/code&gt;, ou alors &lt;a class="link" href="https://krew.sigs.k8s.io/" target="_blank" rel="noopener"
&gt;Krew&lt;/a&gt;, le gestionnaire de plugins kubectl.&lt;/p&gt;
&lt;p&gt;Je lui ai demandé si le processus d&amp;rsquo;acceptation du plugin était complexe. Il a dit que non, je lui ai dit &amp;ldquo;chiche !&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Il a &lt;strong&gt;réalisé l&amp;rsquo;intégralité du processus&lt;/strong&gt; :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Création d&amp;rsquo;un fork de &lt;a class="link" href="https://github.com/kubernetes-sigs/krew-index" target="_blank" rel="noopener"
&gt;krew-index&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Rédaction du manifeste Krew (le fichier &lt;code&gt;.yaml&lt;/code&gt; qui décrit le plugin)&lt;/li&gt;
&lt;li&gt;Prise en compte de toutes les bonnes pratiques demandées par les maintainers de krew-index (format des URLs de téléchargement, descriptions courtes, checksums SHA256, etc.)&lt;/li&gt;
&lt;li&gt;Préparation de la PR, directement sur krew-index&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;J&amp;rsquo;ai juste regardé. La PR a été mergée 12 heures plus tard par les mainteneurs.&lt;/p&gt;
&lt;p&gt;Résultat : &lt;code&gt;kubectl krew install debug-pvc&lt;/code&gt; fonctionne.&lt;/p&gt;
&lt;h2 id="mini-échec---déléguer-aussi-la-démo"&gt;Mini échec - déléguer aussi la démo
&lt;/h2&gt;&lt;p&gt;Fort de ce succès avec la PR pour krew-index, je me suis demandé si on ne pourrait pas faire une démo visuelle (un GIF à ajouter dans le README.md du projet qui montre comment ça fonctionne) avec le LLM.&lt;/p&gt;
&lt;p&gt;Je lui ai demandé s&amp;rsquo;il pouvait le faire avec &lt;code&gt;asciinema&lt;/code&gt; et le LLM m&amp;rsquo;a répondu que &amp;ldquo;oui&amp;rdquo; (oui, je discute avec le LLM comme avec mes collègues). Banco, on a essayé.&lt;/p&gt;
&lt;p&gt;Le résultat était &lt;em&gt;presque&lt;/em&gt; bon, j&amp;rsquo;aurais pu m&amp;rsquo;en contenter si j&amp;rsquo;étais pas quelqu&amp;rsquo;un de pénible : c&amp;rsquo;était un poil lent. J&amp;rsquo;ai l&amp;rsquo;impression la réactivité du LLM dans ses actions était inégale, ce qui rendait le rendu un peu désagréable au visionnage. J&amp;rsquo;aurais pu insister jusqu&amp;rsquo;à avoir quelque chose de correct, mais j&amp;rsquo;ai finalement enregistré moi-même une vidéo, convertie en GIF avec &lt;code&gt;ffmpeg&lt;/code&gt;. C&amp;rsquo;était plus fluide et plus rapide que d&amp;rsquo;itérer.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/03/kubectl-debug-pvc-demo.gif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="le-diff-avec-podsweeper"&gt;Le diff avec PodSweeper
&lt;/h2&gt;&lt;p&gt;La différence de ressenti entre ce projet et PodSweeper est frappante. Là où PodSweeper était un combat constant (race conditions, amnésie du LLM, fonctionnalités hors-spécifications), &lt;code&gt;kubectl-debug-pvc&lt;/code&gt; s&amp;rsquo;est déroulé sans accroc notable.&lt;/p&gt;
&lt;p&gt;Pourquoi ? Je pense que ça tient à la nature du projet :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Une seule chose à faire&lt;/strong&gt;, clairement définie : patcher un subresource Kubernetes avec des volumeMounts&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pas de logique concurrente&lt;/strong&gt; : on fait une requête API, on attend, on s&amp;rsquo;attache&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Un domaine bien documenté&lt;/strong&gt; : l&amp;rsquo;API Kubernetes, Cobra, Bubble Tea. Le LLM connaît tout ça par coeur&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pas d&amp;rsquo;état partagé complexe&lt;/strong&gt; : pas de goroutines qui se marchent dessus, pas de graceful shutdown à gérer, de microservices multiples&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scope limité&lt;/strong&gt; : le projet entier tient dans une quinzaine de fichiers, CI et documentation incluses&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;C&amp;rsquo;est probablement le terrain de jeu idéal pour un LLM. Un problème bien cadré, un domaine technique bien balisé, une solution linéaire.&lt;/p&gt;
&lt;h2 id="quest-ce-que-jen-pense-"&gt;Qu&amp;rsquo;est-ce que j&amp;rsquo;en pense ?
&lt;/h2&gt;&lt;p&gt;Objectivement, ce genre de projet &amp;ldquo;simple&amp;rdquo; (une chose à faire, simple à comprendre) marche &lt;strong&gt;vraiment super bien&lt;/strong&gt; avec OpenCode + Opus. Je pense que c&amp;rsquo;est ce genre à cause (grâce) de ce genre de petits projets que la hype est tellement forte autour du développement agentique. On a une idée en tête qu&amp;rsquo;on avait la flemme de dev, on teste, ça marche. &amp;ldquo;WOW&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Mais je ne veux pas non plus minimiser le travail réalisé. Le fait qu&amp;rsquo;un outil fonctionnel, propre, publié sur Krew et utilisable par n&amp;rsquo;importe qui ait pu émerger d&amp;rsquo;un prompt lancé en début de réunion, c&amp;rsquo;est quand même assez dingue.&lt;/p&gt;
&lt;p&gt;Un peu flippant aussi, de se dire qu&amp;rsquo;un nombre hallucinant de micro tools vont apparaître dans les prochains mois, avec un niveau de qualité probablement inégal.&lt;/p&gt;
&lt;h2 id="le-projet"&gt;Le projet
&lt;/h2&gt;&lt;p&gt;Le code est disponible ici :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/zwindler/kubectl-debug-pvc" target="_blank" rel="noopener"
&gt;https://github.com/zwindler/kubectl-debug-pvc&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Installation :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Via Krew (recommandé)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl krew install debug-pvc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Utilisation interactive (TUI)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl debug-pvc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Utilisation non-interactive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl debug-pvc -n my-namespace -p my-pod-0 -v data:/debug/data
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Si vous aussi vous avez déjà galéré à inspecter un PVC sur un pod sans shell, essayez. Et si vous trouvez des bugs, vous pourrez blâmer le LLM 😄.&lt;/p&gt;</description></item><item><title>GenAI et développement logiciel : retour d'expérience avec PodSweeper</title><link>https://blog.zwindler.fr/2026/03/08/genai-llm-dev-podsweeper/</link><pubDate>Sun, 08 Mar 2026 18:00:00 +0200</pubDate><guid>https://blog.zwindler.fr/2026/03/08/genai-llm-dev-podsweeper/</guid><description>&lt;img src="https://blog.zwindler.fr/2026/02/opencode.webp" alt="Featured image of post GenAI et développement logiciel : retour d'expérience avec PodSweeper" /&gt;&lt;h2 id="la-genai-cest-fantastique-"&gt;La GenAI, c&amp;rsquo;est fantastique ?
&lt;/h2&gt;&lt;p&gt;Pas mal de gens ont sorti leur avis sur la Gen AI pour dev en très peu de temps, alors je me rends compte qu&amp;rsquo;il est plus que temps que je poste ce brouillon commencé il y a plus de deux semaines 🙃.&lt;/p&gt;
&lt;p&gt;Pour le travail, j&amp;rsquo;utilise de plus en plus d&amp;rsquo;assistants IA pour m&amp;rsquo;épauler dans mes tâches du quotidien. En 2024, c&amp;rsquo;était surtout pour automatiser des tâches pénibles (scripter des trucs, faire une liste pénible de tâches répétitives sans coder ça proprement). Courant 2025, j&amp;rsquo;ai testé plusieurs fois de lui faire faire de l&amp;rsquo;Ops et, à chaque fois, les résultats étaient moyens, tant pour concevoir une infra cohérente, fiable et efficiente que pour de l&amp;rsquo;assistance à la résolution d&amp;rsquo;incident (cf. &lt;a class="link" href="https://blog.zwindler.fr/2025/08/15/ops-disparition-suite/#et-dans-linfra-" &gt;mon article sur le sujet&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;En 2026, sur ce dernier point, je trouve qu&amp;rsquo;on n&amp;rsquo;a toujours pas avancé, même si je reconnais qu&amp;rsquo;il existe des outils spécialisés que je n&amp;rsquo;ai pas encore suffisamment testés, open source ou non. Je peux citer &lt;a class="link" href="https://k8sgpt.ai/" target="_blank" rel="noopener"
&gt;k8sgpt&lt;/a&gt; et &lt;a class="link" href="https://github.com/HolmesGPT/holmesgpt" target="_blank" rel="noopener"
&gt;HolmesGPT&lt;/a&gt; en open source, et &lt;a class="link" href="https://www.anyshift.io/" target="_blank" rel="noopener"
&gt;Anyshift&lt;/a&gt; avec son agent SRE pour la détection de root cause et la résolution d&amp;rsquo;incident.&lt;/p&gt;
&lt;p&gt;Note : fun fact, dans son post &amp;ldquo;&lt;a class="link" href="https://alex.balmes.co/fr/blog/mon-positionnement-sur-l-intelligence-artificielle-generative#pour-les-ops" target="_blank" rel="noopener"
&gt;Mon positionnement sur l&amp;rsquo;Intelligence Artificielle Générative&lt;/a&gt;&amp;rdquo; posté juste avant moi, Alex cite une longue liste de métiers qui vont profiter de l&amp;rsquo;IA Gen, et les ops ont le droit à rien d&amp;rsquo;autre qu&amp;rsquo;un argument de plus pour passer sur Kube 😭.&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai en revanche commencé à utiliser la GenAI pour réaliser plusieurs projets de sites web à 100% (&lt;em&gt;vibe coding&lt;/em&gt; ?), dont je vous ai d&amp;rsquo;ailleurs déjà parlé :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2025/12/02/jai-donn%C3%A9-1-heure-%C3%A0-des-agents-copilot-pour-migrer-un-site-de-bloggrify-%C3%A0-hugo/" &gt;Convertir un blog de Bloggrify à Hugo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2026/02/09/101-facons-de-deployer-kubernetes-nouvelle-ui/" &gt;Créer un site &amp;ldquo;joli&amp;rdquo;&lt;/a&gt; (largement au-delà de mes compétences) pour héberger les recherches que j&amp;rsquo;ai faites sur les différentes façons de déployer Kubernetes&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2026/02/20/securite-headers-http-observatory-hugo/" &gt;Améliorer la sécurité de mon site web&lt;/a&gt; en automatisant la modification du thème Hugo que j&amp;rsquo;utilise, de manière à avoir la meilleure note sur Mozilla HTTP Observatory&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Dans les 3 cas, le résultat est là. Ou plutôt, il &lt;em&gt;semble&lt;/em&gt; l&amp;rsquo;être pour le béotien que je suis.&lt;/p&gt;
&lt;p&gt;Je n&amp;rsquo;ai jamais caché que je n&amp;rsquo;ai aucune compétence en front, et peut-être que pour un expert du domaine, ce que j&amp;rsquo;ai fait avec l&amp;rsquo;IA est horrible (ou non ?). Dans tous les cas, ça ne peut pas être pire que les UIs que j&amp;rsquo;ai faites sans. Petit exemple 😄 :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/02/groroti.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="ou-alors--la-gêneai-"&gt;ou alors : la GêneAI ?
&lt;/h2&gt;&lt;p&gt;C&amp;rsquo;est le genre de retours qu&amp;rsquo;on voit fleurir de la part de toutes les personnes qui sont &lt;em&gt;vraiment&lt;/em&gt; expertes d&amp;rsquo;un domaine quand elles voient des novices s&amp;rsquo;extasier. On a de bons exemples avec les vidéos générées par IA : si on ne fait pas attention, on a l&amp;rsquo;impression que c&amp;rsquo;est incroyable. Mais n&amp;rsquo;importe qui avec un œil un peu critique voit tout de suite de &lt;strong&gt;GROS&lt;/strong&gt; problèmes de cohérence. Pareil pour la génération d&amp;rsquo;image, ou de musique.&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est aussi vrai pour le code, et on a de très bons exemples de projets &lt;em&gt;vibe codés&lt;/em&gt; qui sont d&amp;rsquo;immondes plats de spaghetti, et des passoires en termes de cybersécurité. Bref, vous l&amp;rsquo;aurez compris, j&amp;rsquo;ai beau être utilisateur (quotidien), je ne suis pas &amp;ldquo;incroyablé&amp;rdquo; (comme disent mes enfants) par les LLMs, même les meilleurs.&lt;/p&gt;
&lt;p&gt;Pourtant, j&amp;rsquo;ai plusieurs copains qui ne jurent que par ça, notamment des gens bien plus brillants / intelligents (appelez ça comme vous voulez) que moi. Donc je me dis &lt;em&gt;&amp;ldquo;OK, peut-être que je m&amp;rsquo;y prends mal. Essayons avec ce qui se fait de mieux&lt;/em&gt;&amp;rdquo; : un IDE type &amp;ldquo;Claude Code&amp;rdquo; et un modèle Opus.&lt;/p&gt;
&lt;h2 id="léditeur"&gt;L&amp;rsquo;éditeur
&lt;/h2&gt;&lt;p&gt;Après avoir fait une petite étude de marché rapide, on se rend compte que les options sont pléthoriques : Claude Code, OpenCode, Amp Code, &amp;hellip;&lt;/p&gt;
&lt;p&gt;Le problème de Claude Code, c&amp;rsquo;est le ticket d&amp;rsquo;entrée. Je ne suis pas encore prêt à lâcher 100 ou 200 € par mois pour l&amp;rsquo;usage que j&amp;rsquo;en ai aujourd&amp;rsquo;hui. Je ne sais pas si l&amp;rsquo;offre à 20€ me suffirait ou non. Au-delà de rares side projects perso que j&amp;rsquo;ai cités plus haut, je code peu. Le gros de mes geekeries, c&amp;rsquo;est de l&amp;rsquo;infra : installer des Kube et des OS de virtualisation. Des trucs difficiles à automatiser avec un LLM.&lt;/p&gt;
&lt;p&gt;On (Pierre surtout) m&amp;rsquo;a conseillé &lt;a class="link" href="https://ampcode.com/" target="_blank" rel="noopener"
&gt;Amp Code&lt;/a&gt; pour du perso, notamment parce que de base, il y a un tier gratuit avec un certain nombre de tokens et que si on n&amp;rsquo;est pas trop gourmand, c&amp;rsquo;est assez efficace. J&amp;rsquo;ai préféré n&amp;rsquo;en faire qu&amp;rsquo;à ma tête et tester plutôt sur &lt;strong&gt;OpenCode&lt;/strong&gt;, qui a l&amp;rsquo;avantage d&amp;rsquo;être plus flexible sur les providers de LLM et la consommation de tokens. Il est d&amp;rsquo;ailleurs possible de profiter de modèles locaux (gratuits, donc) ou &lt;a class="link" href="https://opencode.ai/docs/fr/zen/" target="_blank" rel="noopener"
&gt;des modèles inclus gratuitement (en tout cas pour l&amp;rsquo;instant) tels que GLM 5 Free&lt;/a&gt;, qui est plutôt bien placé dans les modèles de dev (surtout, c&amp;rsquo;est gratuit&amp;hellip;).&lt;/p&gt;
&lt;p&gt;OK, on a l&amp;rsquo;éditeur. Maintenant, le code ?&lt;/p&gt;
&lt;p&gt;Pour me faire une idée de la pertinence du code généré par mon LLM favori (Sonnet et Opus, depuis un moment), il me faut donc un langage &lt;strong&gt;et&lt;/strong&gt; un cas d&amp;rsquo;usage que je maîtrise, pour être capable de lui dire &lt;em&gt;&amp;ldquo;non mais là, c&amp;rsquo;est n&amp;rsquo;importe quoi !?&amp;rdquo;&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Cas d&amp;rsquo;usage que je maîtrise&amp;hellip; vous vous en doutez, il y aura forcément du &lt;strong&gt;Kubernetes&lt;/strong&gt; dedans.&lt;/p&gt;
&lt;p&gt;Langage que je maîtrise : j&amp;rsquo;ai appris Go en 2022 grâce à un collègue de chez Deezer (encore merci Martial !) et j&amp;rsquo;ai publié quelques outils et fait des contributions mineures. J&amp;rsquo;ai écrit une grande partie de l&amp;rsquo;outil &lt;a class="link" href="https://github.com/deezer/GroROTI" target="_blank" rel="noopener"
&gt;GroROTI&lt;/a&gt; et aussi commencé (mais jamais terminé) le développement d&amp;rsquo;un RPG en Go, fortement inspiré de Castle of the Winds, un jeu de mon enfance : &lt;a class="link" href="https://github.com/zwindler/gocastle" target="_blank" rel="noopener"
&gt;gocastle&lt;/a&gt;. Et j&amp;rsquo;ai une capacité professionnelle (même si ce n&amp;rsquo;est pas le coeur de mon métier) dans mon travail de tous les jours.&lt;/p&gt;
&lt;h2 id="après-le-contexte-le-projet"&gt;Après le contexte, le projet
&lt;/h2&gt;&lt;p&gt;OK, on a le contexte technique : Kube + Go. Reste donc l&amp;rsquo;idée à implémenter. Il faut un projet suffisamment volumineux pour que le test soit pertinent, suffisamment rigolo pour que j&amp;rsquo;aie envie d&amp;rsquo;y passer du temps perso, mais quand même un peu utile pour que j&amp;rsquo;aie envie d&amp;rsquo;en parler et de montrer l&amp;rsquo;avancement. Et surtout, un projet dont la logique métier reste à ma portée : pour évaluer honnêtement la qualité du code produit par l&amp;rsquo;IA, il faut que je sois capable de le relire et de le critiquer.&lt;/p&gt;
&lt;p&gt;Et là, dans mes tiroirs à idées débiles qui débordent de mon cerveau, je me suis souvenu de ce &amp;ldquo;pitch&amp;rdquo; de 2023-2024, que j&amp;rsquo;avais laissé moisir faute de temps :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;PodSweeper&lt;/strong&gt; : la manière la plus complexe, over-engineerée et chaotique de jouer au démineur.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/02/Wat8.webp"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="partez-pas-vous-allez-voir-cest-rigolo-si-"&gt;Partez pas, vous allez voir c&amp;rsquo;est rigolo. Si !
&lt;/h2&gt;&lt;p&gt;Au lieu d&amp;rsquo;une grille visuelle où on clique sur des cases en espérant ne pas tomber sur une &amp;ldquo;mine&amp;rdquo;, on a une &amp;ldquo;grille&amp;rdquo; virtuelle où chaque case est un Pod et le clic est un &lt;code&gt;kubectl delete&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Oui, c&amp;rsquo;est débile. Ça me plaît donc beaucoup :).&lt;/p&gt;
&lt;p&gt;Au-delà du troll assumé (over-engineering des enfers) de ce jeu, il y a quand même un objectif pédagogique derrière.&lt;/p&gt;
&lt;p&gt;Si, si, vraiment.&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai pensé le jeu comme une &lt;strong&gt;introduction à la sécurité dans Kubernetes&lt;/strong&gt;, avec des niveaux de difficulté à débloquer, façon CTF de cybersécurité.&lt;/p&gt;
&lt;p&gt;Au début, vous pouvez &lt;strong&gt;tout&lt;/strong&gt; faire. Vous pouvez bien sûr jouer normalement (delete un Pod, voir s&amp;rsquo;il y a des mines à côté) pour vous faire la main. Vous pouvez aussi automatiser les actions (un script qui &amp;ldquo;clique sur une case&amp;rdquo; au hasard, récupère les hints de proximité de mines, clique à un endroit safe, &amp;hellip;).&lt;/p&gt;
&lt;p&gt;Mais vous pouvez aussi &lt;strong&gt;tricher&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Et c&amp;rsquo;est tout l&amp;rsquo;intérêt du jeu. Dans les premiers niveaux de difficulté, les manifests Kubernetes du jeu sont volontairement vulnérables. On peut donc gagner sans effort, si on sait où chercher.&lt;/p&gt;
&lt;p&gt;Cependant, très vite, les niveaux s&amp;rsquo;enchaînent et les restrictions avec. Assez rapidement, on arrive dans des bonnes pratiques de production qui empêchent toute &amp;ldquo;triche&amp;rdquo;. Et si vous trouvez des vulnérabilités non prévues dans le code du jeu lui-même&amp;hellip; eh bien, c&amp;rsquo;est du bonus 😈.&lt;/p&gt;
&lt;h2 id="le-processus-initial"&gt;Le processus initial
&lt;/h2&gt;&lt;p&gt;C&amp;rsquo;est probablement une erreur, mais j&amp;rsquo;ai fait toute la phase d&amp;rsquo;&lt;strong&gt;idéation avec Gemini&lt;/strong&gt; avant de lancer OpenCode. L&amp;rsquo;expérience aurait probablement été meilleure (a minima plus représentative) si j&amp;rsquo;avais commencé directement avec OpenCode.&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai pondu tout ce que j&amp;rsquo;avais dans la tête, ainsi qu&amp;rsquo;un gros pavé informe de dizaines de lignes provenant de mes notes de quand j&amp;rsquo;ai eu l&amp;rsquo;idée en 2023, et je lui ai demandé de me sortir un fichier &lt;a class="link" href="https://github.com/zwindler/PodSweeper/blob/main/SPECIFICATION.md" target="_blank" rel="noopener"
&gt;SPECIFICATIONS.md&lt;/a&gt; avec toutes les infos importantes, remises dans l&amp;rsquo;ordre.&lt;/p&gt;
&lt;p&gt;Une fois les specs écrites, je lui ai demandé de détailler les différents niveaux et les difficultés que nous allions progressivement ajouter, dans &lt;a class="link" href="https://github.com/zwindler/PodSweeper/blob/main/GAMEPLAY.md" target="_blank" rel="noopener"
&gt;GAMEPLAY.md&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Enfin, j&amp;rsquo;ai demandé de faire un découpage du projet par &amp;ldquo;issues&amp;rdquo; et par priorité, de manière à avoir un MVP rapidement : &lt;a class="link" href="https://github.com/zwindler/PodSweeper/blob/main/ISSUES_PRIORITY.md" target="_blank" rel="noopener"
&gt;ISSUES_PRIORITY.md&lt;/a&gt;. Mon idée était de donner le plan de bataille très détaillé et découpé finement à OpenCode et de lui laisser dérouler.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Première déconvenue&lt;/strong&gt; : Gemini 3 Pro est assez mauvais pour ça. Les tâches étaient crédibles(-ish) mais ordonnées n&amp;rsquo;importe comment (dépendances entre tâches non respectées). J&amp;rsquo;ai donc lancé pour la première fois OpenCode dans mon repo et je lui ai dit &lt;em&gt;&amp;ldquo;voilà le contexte, voilà ce qu&amp;rsquo;on a imaginé comme tâches. Qu&amp;rsquo;est-ce que tu en penses ?&amp;rdquo;&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="le-bon-opencode"&gt;Le bon (open)code&amp;hellip;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/02/opencode.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Dans les trucs assez chouettes : OpenCode + Claude Opus a tout de suite vu que le plan imaginé par Gemini était bancal, et m&amp;rsquo;a posé des questions et proposé un découpage encore imparfait mais déjà plus cohérent. C&amp;rsquo;est probablement là le gros de l&amp;rsquo;intérêt de ces logiciels. Ils embarquent des connaissances pour guider le développement logiciel et surtout (SURTOUT) apportent du cadre.&lt;/p&gt;
&lt;p&gt;Assez vite, on finit par se mettre d&amp;rsquo;accord sur un plan qui me plaît. OpenCode met à jour les documents et se met à développer (scaffolding, création des pipelines, premiers binaires et images Docker vides). On a un projet prêt à développer en un claquement de doigt, c&amp;rsquo;est assez enthousiasmant, de prime abord.&lt;/p&gt;
&lt;p&gt;Les assistants LLMs ont très envie de se jeter dans le code, ça reste vrai avec OpenCode+Opus. Alors même qu&amp;rsquo;on n&amp;rsquo;avait pas fini de discuter du plan et des options possibles, il me proposait de lui-même de passer au code. Cela dit, c&amp;rsquo;était pareil (voire pire) pour Gemini (à qui j&amp;rsquo;avais dit spécifiquement qu&amp;rsquo;on n&amp;rsquo;allait pas faire de code du tout).&lt;/p&gt;
&lt;p&gt;Très vite, les créations de fichiers s&amp;rsquo;enchaînent. J&amp;rsquo;ai du mal à suivre et à chaque pause (quand le LLM a fini une tâche et qu&amp;rsquo;il me demande s&amp;rsquo;il peut passer à la suivante), je prends de longues minutes à lire ce que le LLM a produit. C&amp;rsquo;est à la fois grisant et épuisant (relire tout ça, c&amp;rsquo;est dur pour mon cerveau rouillé).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;La vitesse brute est impressionnante.&lt;/strong&gt; En 3 sessions de 1 à 2h, j&amp;rsquo;ai un MVP fonctionnel. Je comprends qu&amp;rsquo;on parle régulièrement de 10x engineering quand on parle de génération de code avec les LLMs récents. Si on ne parle pas de génération de code brute (ce qui n&amp;rsquo;a pas vraiment de sens), à la louche, le code fonctionnel est généré entre 3x et 10x plus rapidement que ce que j&amp;rsquo;aurais pu faire seul. Des features qui mises bout à bout m&amp;rsquo;auraient pris des heures à implémenter (génération de la grille, logique de reveal, gestion des états de jeu) tombent en quelques minutes. Vous l&amp;rsquo;avez déjà lu ailleurs, je dis pareil - le goulot d&amp;rsquo;étranglement, ce n&amp;rsquo;est plus le code que je tape : c&amp;rsquo;est le code que je dois relire.&lt;/p&gt;
&lt;p&gt;De ce que j&amp;rsquo;ai lu, le code est correct, en particulier lors des premières itérations, un peu moins au bout d&amp;rsquo;un moment. Mais quand je dis &amp;ldquo;correct&amp;rdquo;, je sous-vends peut-être le truc : le code produit est du &lt;strong&gt;Go idiomatique&lt;/strong&gt;. Bonne structure en packages, conventions de nommage respectées, gestion d&amp;rsquo;erreur dans le style Go (quand elle est là&amp;hellip;), utilisation appropriée des interfaces. Ce n&amp;rsquo;est pas juste du code qui compile : c&amp;rsquo;est du code qu&amp;rsquo;un reviewer Go ne rejetterait pas d&amp;rsquo;emblée. On a pour objectif un MVP donc ça reste de la logique &amp;ldquo;métier&amp;rdquo; très simple, mais le socle est propre.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tout est testé&lt;/strong&gt;, très vite le projet contient une couverture parfaite et 100+ tests alors qu&amp;rsquo;on ne fait encore rien. Si c&amp;rsquo;était du code généré par un humain, je ne saurais pas dire si c&amp;rsquo;est une bonne chose. On est pas du tout dans du TDD, beaucoup de code teste des choses inutiles. Dans le cas du code généré par le LLM, c&amp;rsquo;est probablement pour le mieux, car le LLM a tendance à ajouter très régulièrement des régressions (on en reparlera). C&amp;rsquo;est donc intéressant ici, car :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;ça ne coûte quasiment rien en temps de dev (ça va tellement vite à générer)&lt;/li&gt;
&lt;li&gt;cela permet au LLM de se rendre compte que son code introduit une régression, et de fixer de lui-même, sans attendre.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="-et-le-mauvais-opencode"&gt;&amp;hellip; et le mauvais (open)code
&lt;/h2&gt;&lt;p&gt;Côté outil et modèle d&amp;rsquo;abord, quelques &lt;strong&gt;irritants&lt;/strong&gt; :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Par défaut, OpenCode n&amp;rsquo;incite pas le LLM à lancer &lt;code&gt;golangci-lint&lt;/code&gt; à chaque commit. On corrige ça avec un pre-commit hook et/ou les fameux AGENTS.md / skills, mais ça aurait DÛ faire partie du kit de base d&amp;rsquo;un projet golang (il y a bien les tests&amp;hellip;).&lt;/li&gt;
&lt;li&gt;Le LLM (Claude Opus sur OpenCode, mais c&amp;rsquo;est un biais habituel même en dehors) &lt;strong&gt;adore&lt;/strong&gt; les versions de logiciels qui existaient au moment de son entraînement. Il faut continuellement lui répéter que les versions qu&amp;rsquo;il suggère sont obsolètes. C&amp;rsquo;est vrai pour tout : le code Go, les dépendances, les versions des actions GitHub.&lt;/li&gt;
&lt;li&gt;On tombe très souvent dans la limite des 100k tokens. On perd du temps à &amp;ldquo;compacter&amp;rdquo; et on perd de la précision. Typiquement : le LLM me demande s&amp;rsquo;il peut &lt;code&gt;git commit&lt;/code&gt; des modifs, le contexte se compacte avant que je réponde, et il commit sans mon autorisation en redéroulant le contexte. Sur du code aussi peu sensible, ça va. Mais sur de la prod, ça serait un vrai problème.&lt;/li&gt;
&lt;li&gt;Le LLM est souvent amnésique : il oublie qu&amp;rsquo;il a accès à un cluster kind pour faire des tests réels (alors qu&amp;rsquo;il l&amp;rsquo;a fait juste avant la précédente compaction, par exemple).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Côté &lt;strong&gt;qualité du code&lt;/strong&gt; produit, c&amp;rsquo;est plus préoccupant :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Gestion d&amp;rsquo;erreur laxiste.&lt;/strong&gt; Certaines erreurs qui auraient dû retourner un FATAL (controller qui n&amp;rsquo;arrive pas à s&amp;rsquo;initialiser correctement !) sont simplement logguées comme ERROR. On se retrouve à ship des versions qui échouent silencieusement. Là encore, ça doit pouvoir se fine tuner avec un AGENTS.md.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Race conditions.&lt;/strong&gt; Je suis tombé très vite sur des race conditions assez bêtes. Dans mon cas, des pods bloqués en terminating impactaient le jeu suivant (graceful shutdown mal géré). Opus est parti en boucle sans comprendre la source du problème. J&amp;rsquo;ai dû le stopper et lui spécifier qu&amp;rsquo;il ne fallait jamais lancer une nouvelle partie sans s&amp;rsquo;être assuré que la précédente était terminée.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Génération de code en dehors des clous.&lt;/strong&gt; Parfois, sans crier gare, le LLM ajoute une fonctionnalité qui n&amp;rsquo;est pas demandée, inutile, voire qui va à l&amp;rsquo;encontre de la SPECIFICATION écrite précédemment. On est obligé de lui remettre un taquet derrière la tête.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Une fois remis sur les rails, le LLM déroule à nouveau, mais ces épisodes montrent bien que sur du code concurrent ou en dehors de user stories hyper strictes (ce qui sort du workflow de base d&amp;rsquo;opencode), la supervision humaine reste indispensable.&lt;/p&gt;
&lt;p&gt;On me répondra que je débute avec ces outils, et que j&amp;rsquo;aurais pu éviter certains écueils en configurant mieux mon environnement (AGENTS.md, pre-commit hooks, etc.). C&amp;rsquo;est vrai.&lt;/p&gt;
&lt;p&gt;Mais c&amp;rsquo;est justement là que le bât blesse : une des promesses vantées de la GenAI appliquée au dev, c&amp;rsquo;est de permettre à des non-développeurs (ou des débutants) de produire du logiciel de qualité à grande vitesse, de manière à pouvoir ship des logiciels complets. Si pour en tirer le meilleur, il faut déjà être un développeur expérimenté qui sait configurer un environnement complexe (avec les spécificités de ces outils IA), anticiper les race conditions et relire du code concurrent&amp;hellip; on n&amp;rsquo;a pas démocratisé le développement, on a juste donné un outil de plus aux gens qui savaient déjà coder. Mon profil (ops qui code, pas dev pur jus) était précisément le public cible de cette promesse. Et aujourd&amp;rsquo;hui, &amp;ldquo;les calculs sont pas bons, Kévin&amp;rdquo;.&lt;/p&gt;
&lt;h2 id="où-jen-suis-"&gt;Où j&amp;rsquo;en suis ?
&lt;/h2&gt;&lt;p&gt;Depuis tout à l&amp;rsquo;heure, je vous parle de PodSweeper. Mais il en est où, ce projet ?&lt;/p&gt;
&lt;p&gt;Après 3 sessions de 1 à 2h max, sans compter l&amp;rsquo;idéation, j&amp;rsquo;ai un MVP fonctionnel. Comme je l&amp;rsquo;ai dit plus haut, le gain de productivité est indéniable, pour quelqu&amp;rsquo;un qui n&amp;rsquo;est pas &amp;ldquo;dev&amp;rdquo; de métier.&lt;/p&gt;
&lt;p&gt;Le code est probablement &amp;ldquo;globalement&amp;rdquo; de meilleure qualité que le code golang que j&amp;rsquo;aurais pu écrire, &lt;strong&gt;mais&lt;/strong&gt; le LLM laisse passer des trous béants dans la logique métier (tout simplement parce qu&amp;rsquo;il ne réfléchit pas, alors que moi, oui. Enfin, normalement). Dur pour la confiance&amp;hellip; Il faut vraiment rester très méfiant de tout ce qui est produit.&lt;/p&gt;
&lt;p&gt;Le code est disponible à l&amp;rsquo;adresse suivante :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/zwindler/PodSweeper/tree/main" target="_blank" rel="noopener"
&gt;https://github.com/zwindler/PodSweeper/tree/main&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/03/podsweeper.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Vous pouvez aller voir le code pour vous faire une idée. Si vous n&amp;rsquo;avez pas peur de vous spoiler, vous pouvez lire la &lt;a class="link" href="https://github.com/zwindler/PodSweeper/blob/main/SPECIFICATION.md" target="_blank" rel="noopener"
&gt;SPECIFICATION.md&lt;/a&gt; (spoilers), voire &lt;a class="link" href="https://github.com/zwindler/PodSweeper/blob/main/GAMEPLAY.md" target="_blank" rel="noopener"
&gt;GAMEPLAY.md&lt;/a&gt; (j&amp;rsquo;y détaille tous les niveaux donc c&amp;rsquo;est giga spoilers).&lt;/p&gt;
&lt;p&gt;Vous pouvez (normalement) jouer aux premiers niveaux de difficulté. Ça reste assez basique, si vous avez déjà manipulé &lt;code&gt;kubectl&lt;/code&gt; vous devriez trouver la solution très rapidement. Mon but est de rajouter des niveaux au fur et à mesure, j&amp;rsquo;en ai déjà imaginé 10, certains bien retors 😈 et d&amp;rsquo;autres viendront peut-être ensuite.&lt;/p&gt;
&lt;p&gt;Le code est en MPL v2.0 parce que c&amp;rsquo;est une licence copyleft que j&amp;rsquo;aime bien, &lt;a class="link" href="https://www.tldrlegal.com/license/mozilla-public-license-2-0-mpl-2" target="_blank" rel="noopener"
&gt;car elle est à la fois assez peu restrictive, OSI compliant et oblige quand même à reverser les modifs si on en fait dans son coin&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Voilà :) si vous aussi vous trouvez ça rigolo, n&amp;rsquo;hésitez pas à tester et/ou à me faire des retours.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl apply -k https://github.com/zwindler/podsweeper//deploy/base?ref&lt;span class="o"&gt;=&lt;/span&gt;v0.1.4
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;namespace/podsweeper-game created
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl &lt;span class="nb"&gt;wait&lt;/span&gt; --for&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;condition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ready pod -l app.kubernetes.io/name&lt;span class="o"&gt;=&lt;/span&gt;podsweeper &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -n podsweeper-game --timeout&lt;span class="o"&gt;=&lt;/span&gt;60s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pod/gamemaster-54f4dddcc4-6m88z condition met
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Have fun !&lt;/p&gt;</description></item></channel></rss>