Recherche effectué dans :

Cliquez sur un tag pour affiner votre recherche :

Résultat de la recherche (3958 notes) :

J'ai découvert upterm qui permet de partager facilement une session terminal à distance #terminal, #cli, #tooling, #ssh, #JaiDécouvert

J'ai cherché une solution pour partager facilement une session shell de ma workstation à un collègue.

Je connais les solutions suivantes :

$ ngrok tcp 22
Donne : tcp://0.tcp.ngrok.io:12345
# Connexion : ssh user@0.tcp.ngrok.io -p 12345

#JaiDécouvert aujourd'hui les solutions upterm et bore.

Le projet upterm a commencé en 2019 et est codé en Golang. Le projet bore est plus jeune, il a commencé 2022 et est codé en rust.

J'ai testé bore puis upterm. J'ai retenu upterm pour les raisons suivantes :

  • upterm propose directement un package rpm, contrairement à bore
  • Le serveur relais public de upterm était significativement plus réactif que celui de bore lors de mes tests
  • upterm propose nativement une session partagée entre deux utilisateurs, alors que bore est spécialisé dans la création de tunnels TCP. Il est possible de configurer bore pour lancer automatiquement des sessions partagées via un script tmux lancé par ssh, mais c'est moins pratique que upterm

Voici une démonstration de upterm :

$ sudo dnf install -y https://github.com/owenthereal/upterm/releases/download/v0.20.0/upterm_linux_amd64.rpm

Je peux ensuite autoriser la clé publique ssh de l'utilisateur invité :

$ upterm host --authorized-keys PATH_TO_PUBLIC_KEY

ou directement via son username GitHub :

$ upterm host --github-user username

Pour donner accès à une session terminal :

$ upterm host
The authenticity of host 'uptermd.upterm.dev (2a09:8280:1::3:4b89)' can't be established.
ED25519 key fingerprint is SHA256:9ajV8JqMe6jJE/s3TYjb/9xw7T0pfJ2+gADiBIJWDPE.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
╭─ Session: LiZaF6eKfCTxNeFSEt7B ─╮
┌──────────────────┬─────────────────────────────────────────────┐
│ Command:         │ /usr/bin/zsh                                │
│ Force Command:   │ n/a                                         │
│ Host:            │ ssh://uptermd.upterm.dev:22                 │
│ Authorized Keys: │ n/a                                         │
│                  │                                             │
│ ➤ SSH Command:   │ ssh LiZaF6eKfCTxNeFSEt7B@uptermd.upterm.dev │
└──────────────────┴─────────────────────────────────────────────┘

╰─ Run 'upterm session current' to display this again ─╯

🤝 Accept connections? [y/n] (or <ctrl-c> to force exit)
✅ Starting to accept connections...

L'utilisateur invité accède à ce terminal simplement avec :

$ ssh LiZaF6eKfCTxNeFSEt7B@uptermd.upterm.dev

upterm maintient une liste de sessions ouvertes, consultable avec :

$ upterm session list
📡 Active Sessions (1)
═══════════════════════
┌───┬──────────────────────┬──────────────┬─────────────────────────────┐
│   │      SESSION ID      │   COMMAND    │            HOST             │
├───┼──────────────────────┼──────────────┼─────────────────────────────┤
│ * │ DumRFGF6AuinQjzwBf0E │ /usr/bin/zsh │ ssh://uptermd.upterm.dev:22 │
└───┴──────────────────────┴──────────────┴─────────────────────────────┘

💡 Tips:
  • Use 'upterm session current' to see details
  • Use 'upterm session info <SESSION_ID>' for specific session

J'ai découvert croc qui permet de partager facilement du texte ou des fichiers entre deux machines distantes #cli, #tooling

Via Claude Sonnet 4.5, j'ai découvert l'existance des projets croc et Magic Wormhole.

Ces deux projets permettent de partager des fichiers entre deux machines.

Voici un tableau comparatif :

Caractéristique Magic Wormhole croc
Langage Python Go (plus rapide)
Reprise transfert
Multi-fichiers ❌ (un par un)
Vitesse Bon Meilleur
Maturité Plus ancien, stable Plus récent, actif
Stdin/stdout ✅ Excellent ✅ Bon

Claude Sonnet 4.5

J'ai décidé de tester croc.

Sur ma workstation Fedora, j'ai lancé :

$ sudo dnf install -y croc
$ croc --version
croc version v9.6.4-1fce28e
$ croc send --text "Foobar"
Sending 'text' (6 B)
Code is: 8834-lady-protect-senator
On the other computer run

croc 8834-lady-protect-senator

Sur une seconde machine :

$ croc --yes 8834-lady-protect-senator
Receiving text message (6 B)

Receiving (<-192.168.1.108:9009)
Foobar

Ça fonctionne bien, je garde cet outil dans ma boîte à outils 🙂.

Journal du mercredi 24 décembre 2025 à 14:59 #llm, #CodeAssistant, #editor, #Jutilise

Un ami vient de me poser cette question :

tu es content de Mammouth ? ça s'intègre bien à Zed, VSCode ?

Il fait probablement référence à ma note du 2025-11-16_1325.

Comme je l'indiquais à l'époque :

J'ai pris un abonnement d'un mois à 12 € TTC pour tester le service. Pour l'instant, je pense continuer avec le couple Open WebUI et OpenRouter qui me donne accès à plus de modèles et plus de flexibilité.

source

Finalement, je n'ai pas utilisé Mammouth et je suis resté sur le couple Open WebUI et OpenRouter.


Par ailleurs, je n'ai jamais essayé Zed editor et je n'utilise plus VS Code depuis mi-2022 (voir Historique des éditeurs texte que j'ai utilisés).


Voici ce que j'utilise depuis début 2025 pour les LLM :

Au quotidien, j'utilise Open WebUI connecté à OpenRouter pour accéder à différents modèles LLM (voir Quelle est mon utilisation d'OpenRouter.ia ?).

Pour les AI code assistant, j'ai d'abord utilisé avante.nvim, puis depuis quelques mois j'utilise principalement Aider.
Par exemple, j'ai implémenté 90% du projet qemu-compose avec Aider (voir section Development approach).

J'utilise aussi llm (cli), mais sans doute pas encore assez.


Ce que j'envisage de tester :

Avec AIChat et LibreChat, je souhaite commencer à utiliser sérieusement les tools (LLM) et des services MCP.

Ce que je compte conserver : OpenRouter.

J'ai découvert AIChat, alternative à llm cli #artificial-intelligence, #llm, #cli, #JaiDécouvert, #JaimeraisUnJour

Dans ce thread, #JaiDécouvert AIChat (https://github.com/sigoden/aichat), une alternative à llm (cli) codée en Rust.

AIChat is an all-in-one LLM CLI tool featuring Shell Assistant, CMD & REPL Mode, RAG, AI Tools & Agents, and More.

source

En parcourant le README.md, j'ai l'impression que AIChat propose une meilleure UX que llm (cli).

Je constate aussi que AIChat offre plus de fonctionnalités que llm (cli) :

Ce qui attire le plus mon attention, c'est le sous-projet llm-functions qui, d'après ce que j'ai lu, permet de créer très facilement des tools en Bash, Python ou Javascript. Exemples :

J'ai hâte de tester ça 🙂 ( #JaimeraisUnJour ).

Par contre, llm-functions ne semble pas encore permettre la configuration de Remote MCP server.

Je suis aussi intéressé par cette issue : TUI for managing, searching, and switching between chat sessions.

Un point qui m'inquiète un peu : le projet semble peu actif ces derniers mois.

Toujours utiliser unlink pour supprimer un lien symbolique, ne jamais utiliser rm #linux, #btrfs, #mémento, #mémo

Je viens de perdre bêtement la configuration de mon playground LazyVim.

J'utilise ce lien symbolique comme documenté ici :

$ ls -l ~/.config/lazyvim-playground
/home/stephane/.config/lazyvim-playground -> /home/stephane/git/github.com/stephane-klein/lazyvim-playground/config

J'ai voulu nettoyer ma configuration avec mise clean, qui a exécuté :

$ rm -rf ~/.config/lazyvim-playground/

Problème : avec le / à la fin, cette commande ne supprime pas le lien symbolique mais efface tous les fichiers présents dans la cible du lien ! Pour supprimer uniquement le lien, il faut retirer le /.

Leçon de cette erreur : ne jamais utiliser rm pour supprimer un lien symbolique, toujours utiliser unlink :

$ unlink ~/.config/lazyvim-playground/

Je vais profiter de cette erreur pour explorer snapper et timeshift afin de mettre en place un système de snapshot automatique de ma partition /home/ basé sur les fonctionnalités de btrfs.

J'ai découvert la méthode NVIM_APPNAME qui permet de lancer des instances cloisonnées de Neovim #neovim, #JaiDécouvert

Il y a plus d'un an, j'ai écrit cette note où je décrivais la méthode que j'avais trouvée après plusieurs itérations pour lancer plusieurs instances Neovim cloisonnées.

J'ai publié cette méthode dans neovim-playground, qui ressemble à ceci :

export XDG_CONFIG_HOME=$(PWD)/config/
export XDG_DATA_HOME=$(PWD)/local/share/
export XDG_STATE_HOME=$(PWD)/local/state/
export XDG_CACHE_HOME=$(PWD)/local/cache/

Je me suis senti un peu bête aujourd'hui en découvrant dans la documentation officielle de Neovim qu'il existe une méthode officielle pour isoler une instance Neovim :

Cette fonctionnalité a été ajoutée dans la version 0.9.0 d'avril 2023, suite à une demande d'utilisateurs qui avaient le même besoin que moi, décrite dans cette issue : NVIM_APPNAME: isolated configuration profiles

Dans cette documentation, #JaiDécouvert comment lancer une application dans un namespace cgroups :

$ systemd-run --user -qt -p PrivateUsers=yes -p BindPaths=/home/user/profile_xy:/home/user/.config/nvim nvim

Je trouve cela plutôt simple.
Coïncidence : j'ai découvert systemd-run il y a 3 mois et depuis, je croise cette commande de plus en plus souvent.

Comme je souhaite lancer un environnement cloisonné Neovim tout en conservant l'accès aux outils de mon terminal (comme ceux installés avec Mise), j'ai choisi d'utiliser la méthode basée sur NVIM_APPNAME.

J'ai testé cette méthode avec succès dans neovim-playground (commit).

J'ai découvert le concept de "catch up culture" #JaiDécouvert, #NouveauMot, #communication

Temps de lecture : 4 minutes

J'ai été heureux de découvrir le 5 décembre dernier, #NouveauMot pour exprimer un concept que j'observe depuis des années : "catch up culture".

Voici le parcours médiatique du concept :

Et le 5 décembre, ma compagne me fait découvrir le terme catch up culture.


La "catch up culture" c'est quand on voit ses amis uniquement pour se raconter ce qu'on a fait depuis la dernière fois, plutôt que de vivre des moments ensemble. Les amitiés deviennent alors des séances de rattrapage espacées (que ce soit de 2 mois, 6 mois, 1 an ou 2 ans) où on échange surtout des anecdotes et des souvenirs communs. On reste sur les grandes lignes sans rentrer dans les détails importants, de peur d'ennuyer l'autre, parce qu'au fond on ne fait plus vraiment partie de sa vie.

Je le vis régulièrement quand je retourne à Metz une à deux fois par an, pour voir mes amis pongistes par exemple, avec qui j'ai vécu pendant parfois plus de 10 ans des aventures humaines mémorables. Même chose avec d'anciens collègues.

J'ai énormément de mémoire transactive avec eux. Quand je les revois, c'est fluide, ils me sont familiers, j'ai l'impression de les avoir vus hier. Ils sont importants pour moi. J'ai l'impression de les connaître avec un assez haut niveau d'intimité. Je connais leurs forces et faiblesses, j'ai confiance en eux, ce sont de vrais amis.

Par contre, à chaque fois que je les vois, j'ai la même sensation : on tourne en rond, on pratique du "catch up". On se raconte encore et encore nos anecdotes communes, nos souvenirs communs. On ne fait plus rien ensemble à part partager un bon repas. Plus de nouveaux "faits d'arme" !

Je n'aime pas et je n'ai jamais aimé pratiquer le small talk ou faire du baratinage. J'aime apprendre des choses des autres, et pour ça j'aime aller dans le détail, dépasser le catalogue de leurs dernières vacances ou de leurs aménagements de maison secondaire. Pour cela, j'essaie de privilégier des rencontres one-on-one (en tête-à-tête). J'ai découvert cela notamment dans le livre Never Eat Alone que j'ai survolé en 2016.

Je constate que les discussions en tête-à-tête sont d'autant plus intéressantes avec des amis avec qui on est en très forte confiance. Elles permettent :

  • Profondeur de connexion : Les conversations en tête-à-tête permettent d'aller au-delà des banalités, et donc des échanges purement catch up, pour vraiment comprendre les motivations, défis et aspirations de l'autre personne.
  • Vulnérabilité et confiance : Il est plus facile d'être authentique et de partager des choses personnelles dans un cadre intimiste.
  • Attention non divisée : On peut vraiment écouter et être présent, sans les distractions d'un groupe et surtout, sans avoir peur d'ennuyer tout le monde en entrant dans les détails.

C'est un peu dans l'espoir de passer tout de suite au-delà de l'étape "catch up" que j'ai créé ma page NowNowNow, sans toutefois me faire d'illusion. En dehors de 1 ou 2 amis, personne ne connaît ou ne consulte cette page. Mais ça n'a pas d'importance pour moi, je le fais quand même, l'idée me plaît.

Quelques jours avant un dîner en tête-à-tête, j'aime prendre le temps de penser aux sujets de conversation qui pourraient nous intéresser tous les deux : partager mes nouvelles découvertes, mes nouveaux concepts et avoir le point de vue de la personne. J'aime savoir quels sont ses défis actuels, et j'essaie de lui poser des questions dans ce sens, pour lui permettre de formaliser sa pensée et pour apprendre d'elle, découvrir de nouvelles situations.

La prochaine fois que je vous propose une rencontre en tête-à-tête, vous saurez pourquoi 🙂.

J'ai découvert le terme "Un trope" (fiction) #vocabulaire, #NouveauMot

Dans la vidéo "La folle histoire des machines qui parlent ! avec Monsieur Phi et Tiffany" du Vortex, Monsieur Phi m'a fait découvrir un #NouveauMot, "un trope" :

Dans le domaine de la fiction, un trope désigne un élément narratif récurrent, facilement reconnaissable par le public, qui sert de base ou d'ingrédient commun à de nombreuses œuvres, quel que soit leur genre ou média (littérature, théâtre, cinéma, série télévisée, jeu vidéo, bande dessinée, etc.). Les tropes contribuent à établir des connexions de sens et des échos culturels entre différentes histoires, facilitant ainsi la compréhension et l'engagement du public.

wikipedia

Script d'analyse des coûts Aider à partir de l'historique #astuce, #CodeAssistant

J'ai cherché une fonctionnalité pour calculer le coût total de l'utilisation d'Aider sur un projet. Je n'ai rien trouvé dans la documentation ni dans les issues du projet Aider.

Je sais qu'Aider enregistre toutes les informations de session dans .aider.chat.history.md.

Ce fichier contient des lignes du type : "Tokens: 49k sent, 1.9k received. Cost: $0.17 message, $1.68 session".

À partir de ces informations, j'ai généré avec Claude Sonnet 4.5 le script Python aider_cost_analyzer.py.

Installation sous Fedora :

$ mkdir -p ~/.local/bin
$ curl -o ~/.local/bin/aider_cost_analyzer.py https://gist.githubusercontent.com/stephane-klein/3b3808c1b03b7e6ddfc4b22b69fdf776/raw/4262faec0cb2f468ea6b6d8751339b8e8497f005/aider_cost_analyzer.py
$ chmod +x ~/.local/bin/aider_cost_analyzer.py

Exemple d'utilisation :

$ aider_cost_analyzer.py .
Analyzing 1 history file(s) in '.':

.aider.chat.history.md:
  Messages: 30
  Tokens sent: 639,200 | received: 65,613
  Cost: $1.86

============================================================
Total tokens sent: 639,200
Total tokens received: 65,613
Total cost: $1.86

J'ai posté l'issue suivante dans le repository aider-ce : "Calculate cumulative token usage and cost across all Aider sessions".

J'ai découvert l'extension Firefox Unlock Medium Article #firefox, #JaiDécouvert

#JaiDécouvert extension Firefox pour bypass l'obligation de créer un compte Medium pour consulter un article des articles Medium : Unlock Medium article.

L'extension se base sur le site web : https://freedium.cfd.

net-tools est déprécié, je dois remplacer "lsof -i" par "ss -tlnp" #linux, #kernel, #network

J'utilise habituellement lsof -i | grep "8080" pour identifier le processus qui écoute sur le port 8080.

Comme je le mentionnais dans 2025-07-04_1614, j'ai appris net-tools au début des années 2000 et j'ai gardé cette habitude depuis.

D'après Claude Sonnet 4.5, iproute2 est devenu le standard dans Debian, Ubuntu et Fedora vers 2013-2015. net-tools a été supprimé de l'installation par défaut entre 2017 et 2018.


lsof (pour LiSt Open Files) interroge /proc pour récupérer les informations. Cette implémentation, comme tous les outils net-tools, est ancienne et n'utilise pas l'API moderne Netlink.

En 2025, la méthode recommandée pour identifier les processus écoutant des ports est cette commande iproute2 (code source) :

$ ss -tlnp | grep 8080

Explication des options :

  • -t: TCP sockets
  • -l: Listening sockets uniquement
  • -n: Affichage numérique (pas de résolution DNS)
  • -p: Affiche les processus

J'ai écrit cette note et bridge-utils est déprécié, je dois remplacer "brctl" par "ip link" pour m'aider à adopter les commandes modernes iproute2.


Pour apprendre cette nouvelle commande, j'ai ajouté la carte-mémoire suivante dans Anki :

Je dois utiliser journalctl -t en non pas jounalctl -u #aide-mémoire, #mémento, #mémo

Note de type #mémo sur l'utilisation de la commande journalctl.

En travaillant sur un playground d'étude de Podman Quadlets, j'ai affiché cette sortie journalctl :

$ journalctl
Dec 02 05:43:42 stephane-coreos systemd[1]: rpm-ostreed.service: Deactivated successfully.
Dec 02 05:43:42 stephane-coreos audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='unit=rpm-ostreed comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? ad>
Dec 02 05:43:50 stephane-coreos chronyd[914]: Selected source 172.234.184.36 (2.fedora.pool.ntp.org)
Dec 02 05:44:42 stephane-coreos kernel: evm: overlay not supported
Dec 02 05:44:42 stephane-coreos podman[1308]: 2025-12-02 05:44:42.996190724 +0000 UTC m=+0.092291988 container remove 5c6247f1c702c3c36f167fd1477b69e2de254df36f987d78d01084683213a09a (image=docker.io/library/post>
Dec 02 05:44:43 stephane-coreos podman[1308]: 2025-12-02 05:44:43.051005068 +0000 UTC m=+0.147106332 volume remove b83aa9fc3fccf2b416e8c9d96cd52892e473df586cae8d37f3c009cee96e1605
Dec 02 05:44:43 stephane-coreos podman[1308]: 2025-12-02 05:44:43.051364949 +0000 UTC m=+0.147466223 system refresh
Dec 02 05:44:43 stephane-coreos systemd[1163]: Created slice session.slice - User Core Session Slice.
Dec 02 05:44:43 stephane-coreos systemd[1163]: Starting dbus-broker.service - D-Bus User Message Bus...
Dec 02 05:44:43 stephane-coreos systemd[1163]: Started dbus-broker.service - D-Bus User Message Bus.
Dec 02 05:44:43 stephane-coreos dbus-broker-launch[1323]: Policy to allow eavesdropping in /usr/share/dbus-1/session.conf +31: Eavesdropping is deprecated and ignored
Dec 02 05:44:43 stephane-coreos dbus-broker-launch[1323]: Policy to allow eavesdropping in /usr/share/dbus-1/session.conf +33: Eavesdropping is deprecated and ignored
Dec 02 05:44:43 stephane-coreos dbus-broker-launch[1323]: Ready
Dec 02 05:44:43 stephane-coreos systemd[1163]: Created slice user.slice - Slice /user.
Dec 02 05:44:43 stephane-coreos systemd[1163]: Started podman-1308.scope.
Dec 02 05:44:43 stephane-coreos systemd[1163]: Started podman-pause-a99918d0.scope.
Dec 02 05:44:49 stephane-coreos irqbalance[920]: Cannot change IRQ 26 affinity: Permission denied
Dec 02 05:44:49 stephane-coreos irqbalance[920]: IRQ 26 affinity is now unmanaged

Pour filtrer uniquement les entrées podman, j'ai lancé :

$ journalctl -u podman
-- No entries --

Contrairement à ce que j'attendais, cette commande n'a retourné aucun résultat.

En creusant le sujet, j'ai découvert que la 3ᵉ colonne (qui contient podman) ne correspond pas au nom de la systemd Unit qui a créé le message log, mais au champ SYSLOG_IDENTIFIER. Voici la structure des champs dans le format par défaut (short) de journalctl :

Dec 02 05:44:43 stephane-coreos podman[1308]: message text
│              │                │       │      │
│              │                │       │      └─ MESSAGE
│              │                │       └─ _PID
│              │                └─ SYSLOG_IDENTIFIER
│              └─ _HOSTNAME
└─ __REALTIME_TIMESTAMP (formaté)

Pour filtrer sur le champ SYSLOG_IDENTIFIER, il faut utiliser l'option -t :

-t, --identifier=SYSLOG_IDENTIFIER¶

    Show messages for the specified syslog identifier SYSLOG_IDENTIFIER.

    This parameter can be specified multiple times.

    Added in version 217.paramètre
stephane@stephane-coreos:~$ journalctl -t podman
Dec 02 05:44:42 stephane-coreos podman[1308]: 2025-12-02 05:44:42.996190724 +0000 UTC m=+0.092291988 container remove 5c6247f1c702c3c36f167fd1477b69e2de254df36f987d78d01084683213a09a (image=docker.io/library/postgres:18.1, name=systemd-postgresql, PODMAN_SYSTEMD_UNIT=postgresql.service)
Dec 02 05:44:43 stephane-coreos podman[1308]: 2025-12-02 05:44:43.051005068 +0000 UTC m=+0.147106332 volume remove b83aa9fc3fccf2b416e8c9d96cd52892e473df586cae8d37f3c009cee96e1605
Dec 02 05:44:43 stephane-coreos podman[1308]: 2025-12-02 05:44:43.051364949 +0000 UTC m=+0.147466223 system refresh

Le nom -t de l'option vient de l'option --tag de logger :

$ logger --help

Usage:
 logger [options] [<message>]

Enter messages into the system log.

Options:
 ...
 -t, --tag <tag>          mark every line with this tag
 ...

Mon manque de maîtrise de journalctl illustre bien ce que j'évoquais dans 2025-07-04_1614.
J'utilise Linux depuis 1999, et l'arrivée de systemd a bouleversé pas mal de choses.
Cette transition a créé de la confusion chez moi, et je n'ai jamais vraiment pris le temps d'étudier sérieusement systemd.

J'ai découvert class-variance-authority et tailwinds-variants #ReactJS, #svelte, #WebDev, #JaiDécouvert

Jusqu'à présent, pour la gestion conditionnelle des classes CSS dans mes projets ReactJS ou Svelte, j'utilisais clsx.
Pour Svelte en particulier, j'utilise souvent directement le mécanisme conditionnel natif de l'attribut "class" du framework.

Aujourd'hui, dans un projet professionnel ReactJS, #JaiDécouvert la librairie conditionnelle class-variance-authority.

Cette librairie existe depuis debut 2022 et voici un exemple d'utilisation de class-variance-authority :

<script>
  import { cva } from 'class-variance-authority';

  const button = cva(
    'font-semibold rounded', // équivalent au paramètre `base:` utlisé par tailwind-variants 
    {
	    variants: {
	      intent: {
	        primary: 'bg-blue-500 text-white hover:bg-blue-600',
	        secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300'
	      },
	      size: {
	        sm: 'px-3 py-1 text-sm',
	        md: 'px-4 py-2 text-base',
	        lg: 'px-6 py-3 text-lg'
	      }
	    },
	    compoundVariants: [
	      {
	        intent: 'primary',
	        size: 'lg',
	        class: 'uppercase tracking-wide' // <= appliqué seulement si intent="primary" et size="lg"
	      }
	    ],
	    defaultVariants: {
	      intent: 'primary',
	      size: 'md'
	    }
    }
  );

  export let intent = 'primary';
  export let size = 'md';
</script>

<button class={button({ intent, size })}>
  <slot />
</button>

Je trouve cette approche plus élégante que clsx pour des besoins complexes, comme la création d'un design system.


Dans la même famille de librairie, il existe aussi tailwind-merge que j'avais déjà identifié mais sans avoir jamais pris le temps d'étudier. Ses fonctionnalités sont très simples et minimalistes :

Merge Tailwind CSS classes without style conflicts

source


Claude Sonnet 4.5 m'a fait découvrir tailwind-variants, une alternative à class-variance-authority. Cette lib est spécifique à Tailwind CSS mais offre de meilleures performances et des fonctionnalités supplémentaires par rapport à class-variance-authority.
Le projet a été créé début 2023, soit environ 1 an après class-variance-authority.

Voici un tableau comparant les fonctionnalités de tailwind-variants et class-variance-authority :

La dernière section de la page Tailwind Variants - Comparison explique l'historique de la lib avec class-variance-authority et les raisons qui ont motivé sa création.

Après quelques difficultés, je pense avoir saisi l'intérêt de la fonctionnalité "slots", disponible dans tailwind-variants mais absente de class-variance-authority.


Si un jour je dois créer des composants de design system avancés dans un projet ReactJS ou Svelte, je pense que j'utiliserai tailwind-variants.

J'ai découvert Adminer, alternative à PhpMyAdmin et je me suis intéressé à OPCache #php, #mysql, #WebDev, #JaiDécouvert

En travaillant sur un playground d'étude de Podman Quadlets, dans le README.md de l'image Docker mariadb, #JaiDécouvert le projet Adminer (https://www.adminer.org) qui semble être l'équivalent de PhpMyAdmin, mais sous la forme d'un fichier unique.

Je découvre aussi que contrairement à PhpMyAdmin, Adminer n'est pas limité à Mysql / MariaDB, il supporte aussi PostgreSQL.

En regardant le dépôt GitHub d'Adminer, je découvre que le gros fichier PHP de 496 kB est le résultat de la concaténation de nombreux fichiers php.
Ça me rassure, parce que je me demandais comment l'édition d'un fichier unique de cette taille pouvait être humainement gérable.

Je trouve astucieux ce mode de déploiement d'un projet PHP sous forme d'un seul fichier qui me fait penser à la méthode Golang. Cependant, je me pose des questions sur la performance de cette technique étant donné que PHP fonctionne en mode process-per request (CGI), ce qui signifie que ce gros fichier PHP est interprété à chaque action sur la page 🤔.

En creusant un peu le sujet avec Claude Sonnet 4.5, je découvre que depuis la version 5.5 de PHP, OPCache améliore significativement la vitesse des requêtes PHP, sans pour autant atteindre celle de Golang, NodeJS, Python ou Ruby qui utilisent des serveurs HTTP intégrés. La consommation mémoire reste supérieure dans des conditions d'implémentation comparables.
Avec OPCache, Adminer semble rester performant malgré l'utilisation d'un fichier unique.

Script qui permet de transformer automatiquement du texte en anglais en fichier audio #anglais, #astuce

J'ai généré avec Claude Sonnet 4.5 le script Python text_to_audio.py. Il me permet de transformer automatiquement du texte en anglais en fichier audio mp3.
J'intègre ensuite ces fichiers dans mes carte-mémoire Anki pour travailler mon anglais.

Installation sous Fedora :

$ mkdir -p ~/.local/bin
$ curl -o ~/.local/bin/text_to_audio.py https://gist.githubusercontent.com/stephane-klein/1406e746f0253956062d4adff7a692bd/raw/8571cdd91cae8ebcd208435daacf431cfc1cd353/text_to_audio.py
$ chmod +x ~/.local/bin/text_to_audio.py

Exemple d'utilisation :

$ text_to_audio.py "Reinforcement Learning from Human Feedback"
Downloading audio for: 'Reinforcement Learning from Human Feedback'
Language: en-GB
URL: https://translate.google.com/translate_tts?ie=UTF-8&tl=en-GB&client=tw-ob&q=Reinforcement+Learning+from+Human+Feedback
Saving to: /home/stephane/english_audio/2025-12-01_Reinforcement_Learning_from_Human_Feedback.mp3

✓ Successfully downloaded to '/home/stephane/english_audio/2025-12-01_Reinforcement_Learning_from_Human_Feedback.mp3'
File size: 28224 bytes

J'utilise actuellement un endpoint HTTP de Google Translator pour générer les fichiers audio, en attendant de trouver une alternative plus open source / communautaire.

Journal du lundi 24 novembre 2025 à 14:35 #MachineLearning, #embeddings, #JaiÉcouté, #JaimeraisUnJour

#JaiÉcouté la vidéo "NLP : Comprendre le Word Embedding à travers Word2Vec" du professeur Jaouad Dabounou. Elle m'a aidé à comprendre les bases du fonctionnement de word2vec. Je l'ai trouvée plutôt accessible.

#JaimeraisUnJour approfondir le sujet et peut-être construire un petit embeddings Models basé sur word2vec pour le tester. Je ne suis pas certain que ce soit à ma portée, mais l'exercice m'intéresse.

Journal du vendredi 21 novembre 2025 à 14:32 #embeddings, #llm, #JaiDécouvert

Via Claude Sonnet 4.5, #JaiDécouvert le projet Massive Text Embedding Benchmark qui compare les embeddings Models.

Voici le site de documentation, son dépôt GitHub, et son leaderboard qui liste actuellement 319 models, dont 180 supportant le français.

OpenRouter.ai propose maintenant des embeddings models #llm

Il y a quelques mois, j'ai posté le message suivant sur Reddit et je l'ai aussi envoyé par mail au support OpenRouter :

Bonjour,

Sauf erreur de ma part, openrouter.ai ne semble pas proposer d'API de Vector embeddings, comme text-embedding-3-small ou text-embedding-3-large d'OpenAI. Ni voyage-3-large, voyage-3.5 , etc d'Anthropic.

Quelques questions :

  • Y a-t-il une raison technique particulière à cette absence ?
  • S'agit-il d'un choix stratégique produit ?
  • Cette fonctionnalité est-elle prévue dans votre roadmap ?

Merci pour votre produit, félicitations !
Stéphane

Deux jours plus tard, j'ai eu la réponse mail suivante :

Hi Stéphane,

Thanks for the thoughtful note and for sharing your observations. You're right — embeddings aren’t currently available via OpenRouter.

While I can’t share exact timelines, I can say it's something we’re actively thinking about. We appreciate the interest and are keeping a close eye on demand and technical feasibility.

Thanks again for the kind words and for using OpenRouter.

Le 5 novembre 2025, j'ai eu la bonne surprise de découvrir par mail qu'OpenRouter supporte maintenant des modèles d'embedding :

La pages OpenRouter Embeddings Models contient une liste de 22 models :

J'ai posté le message suivant sur Reddit :

OpenRouter a annoncé par mail le 5 novembre 2025 qu'ils supportent maintenant les Embedding models. Leur catalogue compte actuellement 22 modèles, provenant entre autres d'OpenAI, Qwen, Mistral et Google.

Au moment où j'écris ces lignes, cette information ne figure pas encore sur https://openrouter.ai/announcements.

source

Journal du vendredi 21 novembre 2025 à 12:03 #CodeAssistant, #open-source, #llm, #JaiDécouvert, #JaiLu

Dans ce thread, #JaiDécouvert OpenCode (https://github.com/sst/opencode) qui semble être une alternative à Aider et Claude Code.

Après avoir parcouru la documentation, j'ai l'impression qu'OpenCode propose des fonctionnalités et une User experience plus avancées qu'Aider.

Le projet est récent (démarré en mars 2025) et publié sous licence MIT.

D'après le footer du site de documentation, je comprends qu'OpenCode est développé par l'entreprise Anomaly, financée par du Venture capital.

#JaiLu ce commentaire à propos d'OpenCode dans les issues d'Aider.

En cherchant sur Hacker News, je suis tombé sur ce thread de juillet 2025.

J'ai retenu ce commentaire :

Two big differences:

  1. opencode is much more "agentic": It will just take off and do loads of stuff without asking, whereas aider normally asks permission to do everything. It will make a change, the language server tells it the build is broken, it goes and searches for the file and line in the error message, reads it, and tries to fix it; rinse repeat, running (say) "go vet" and "go test" until it doesn't see anything else to do. You can interrupt it, of course, but it won't wait for you otherwise.

  2. aider has much more specific control over the context window. You say exactly what files you want the LLM to be able to see and/or edit; and you can clear the context window when you're ready to move on to the next task. The current version of opencode has a way to "compact" the context window, where it summarizes for itself what's been done and then (it seems) drops everything else. But it's not clear exactly what's in and out, and you can't simply clear the chat history without exiting the program. (Or if you can, I couldn't find it documented anywhere.)

source)

Je retiens donc qu'Aider offre un contrôle plus précis qu'OpenCode. OpenCode fonctionne de manière plus autonome.

Pour ma part, je préfère contrôler finement les actions d'un AI code assistant sur mon code, à la fois pour comprendre ses interventions et pour gérer ma consommation de tokens.

Je n'ai pas envie de tester OpenCode pour le moment, je vais continuer avec Aider.

Journal du dimanche 16 novembre 2025 à 22:17 #projet-34, #vpn, #admin-sys

Suite à publication des notes "Setup Fedora CoreOS avec LUKS et TPM, non sécurisé contre le vol physique de serveur", "Setup Fedora CoreOS avec LUKS et Tang", j'ai réfléchi à mes prochaines itérations du Projet 34 - "Déployer un cluster k3s et Kubevirt sous CoreOS dans mon Homelab".

Je souhaite réaliser et publier un playground pour étudier et tester les solutions VPN suivantes :

Dans un premier temps, je souhaite pouvoir accéder en ssh aux serveurs de mon Homelab depuis n'importe où. L'objectif est d'utiliser une méthode unique pour me connecter à ces serveurs en utilisant simplement leur hostname, sans avoir à gérer leurs adresses IP locales ni à configurer manuellement des entrées DNS.

Je souhaite tester l'installation de ces solutions sur des serveurs sous CoreOS, ma workstation sous Fedora et sous Android.

Idéalement, je souhaite configurer les services netbird et Tailscale via Terraform.

Je ne pense pas tester tout le suite headscale.

Journal du dimanche 16 novembre 2025 à 13:25 #llm, #JaiDécouvert

Dans la vidéo de Monsieur Phi "L'autonomie des IA expliquée aux humains", #JaiDécouvert le service Mammouth, qui me rappelle un peu OpenRouter.

J'ai pris un abonnement d'un mois à 12 € TTC pour tester le service. Pour l'instant, je pense continuer avec le couple Open WebUI et OpenRouter qui me donne accès à plus de modèles et plus de flexibilité.

L'objectif produit de Mammouth ressemble pas mal au projet Albert Conversation sur lequel j'ai travaillé à la DINUM entre avril et août 2025.

Journal du dimanche 16 novembre 2025 à 11:06 #vidéo, #llm

Je viens d'écouter une nouvelle vidéo de Monsieur Phi au sujet des LLM : "L'autonomie des IA expliquée aux humains". Je l'ai trouvée excellente, tout comme celle que j'avais mentionnée dans la note de décembre 2024.

J'ai apprécié tout particulièrement :

J'ai découvert que le livre de Monsieur Phi, "La parole aux machines - Philosophie des grands modèles de langage" est enfin sorti ! Je viens de l'acheter 🙂.

Journal du samedi 15 novembre 2025 à 14:23 #DevOps, #open-source, #JaiDécouvert

Dans ce commentaire, #JaiDécouvert une alternative à Grafana (partie dashboard) : Perses (https://github.com/perses/perses).

For exclusively dashboards, the CNCF has https://perses.dev/, which supports Prometheus Loki and Pyroscope, and has a Grafana importer but I haven't given it a shot.

source

Setup Fedora CoreOS avec LUKS et Tang #linux, #security, #admin-sys, #CoreOS

Il y a quelques jours, dans ma note "Setup Fedora CoreOS avec LUKS et TPM", je disais :

Attention, j'ai découvert que cette méthode n'est pas sécurisée en cas de vol physique du serveur !

Si un attaquant boot depuis un autre disque avec le même firmware et le même kernel, il pourra extraire en clair la clé LUKS stockée dans le TPM 🫣.

source

Une solution pour traiter ce point faible est d'utiliser un pin éloigné physiquement du serveur qui l'utilise.

Le framework Clevis utilise le terme "pins" pour désigner les différents méthodes de déverrouillage d'un volume LUKS.

Origine du mot "pin" ?
Claude Sonnet 4.5 m'a expliqué que le terme "pin", qui se traduit par "goupille" en français, désigne la pièce mécanique qui bloque l'ouverture d'un cadenat.

Par exemple, dans un contexte self hosting dans un homelab, je peux héberger physiquement un serveur dans mon logement et le connecter à un pin sur un serveur Scaleway ou sur un serveur dans le homelab d'un ami.

Les pins distants, accessibles via réseau, sont appelés serveurs Network-Bound Disk Encryption.

Si le serveur Network-Bound Disk Encryption est configuré pour répondre uniquement aux requêtes provenant de l'IP de mon réseau homelab, en cas de vol du serveur, le voleur ne pourra pas récupérer le secret permettant de déchiffrer le volume LUKS.

Dans le playground install-coreos-iso-on-qemu-with-luks-and-tang, j'ai testé avec succès le déverrouillage d'un volume LUKS avec un serveur Network-Bound Disk Encryption nommé tang.

Pour être précis, dans la configuration de ce playground, deux pins sont obligatoires pour déverrouiller automatiquement le volume : un pin tang et un pin TPM2. Le nombre minimum de pins requis pour le déverrouillage est défini par le paramètre threshold.

clevis, qui permet de configurer les pins et de gérer la récupération de la passphrase à partir des pins, utilise l'algorithme Shamir's secret sharing (SSS) pour répartir le secret à plusieurs endroits.

Voici quelques scénarios de conditions de déverrouillage que clevis permet de configurer grâce à SSS :

  • TPM2 ou Tang serveur 1
  • TPM2 et Tang serveur 1
  • Tang serveur 1 ou Tang serveur 2
  • 2 parmi Tang serveur 1, Tang serveur 2, Tang serveur 3
  • ...

Si les conditions ne sont pas remplies, systemd-ask-password demande à l'utilisateur de saisir sa passphrase au clavier.


Je n'ai pas trouvé d'image docker officielle de tang. Toutefois, j'ai trouvé ici l'image non officielle padhihomelab/tang (son dépôt GitHub : https://github.com/padhi-homelab/docker_tang).
Dans mon playground, je l'ai déployé dans ce docker-compose.yml.


J'ai trouvé la configuration butane de tang simple à définir (lien vers le fichier) :

  luks:
    - name: var
      device: /dev/disk/by-partlabel/var
      wipe_volume: true
      key_file:
        inline: password
      clevis:
        tpm2: true
        tang:
          - url: "http://10.0.2.2:1234"
            # $ docker compose exec tang jose jwk thp -i /db/pLWwUuLhqqFb-Mgf5iVkwuV4BehG9vzd2SXGMyGroNw.jwk
            # pLWwUuLhqqFb-Mgf5iVkwuV4BehG9vzd2SXGMyGroNw
            thumbprint: dx9dNzgs-DeXg0SCBQW5rb7WQkSIN1B8MIgcO6WxJfI
        threshold: 2 # TMP2 + Tang (or passphrase keyboard input)

La seule complexité que j'ai rencontrée est la méthode pour récupérer le paramètre thumbprint de l'instance tang.

Voici la méthode que j'ai utilisée :

$ docker compose exec tang jose jwk thp -i /db/pLWwUuLhqqFb-Mgf5iVkwuV4BehG9vzd2SXGMyGroNw.jwk
pLWwUuLhqqFb-Mgf5iVkwuV4BehG9vzd2SXGMyGroNw

Autre difficulté, il faut ajouter les arguments kernel suivants pour activer l'accès réseau dès le début du process de boot afin de permettre à clevis d'accéder au serveur tang :

variant: fcos
version: 1.6.0
kernel_arguments:
  should_exist:
    - ip=dhcp
    - rd.neednet=1


J'ai intégré au README.md du playground une section nommée "How to switch from 2 required ping to 1 or the opposite?", pour documenter comment modifier à chaud la configuration clevis.
Par exemple pour changer de serveur tang ou modifier le nombre de pins nécessaires pour déverrouiller la partition chiffrée.


Il est conseillé d'activer le pin TPM2 en complément de tang pour éviter ce type d'attaque décrit par Claude Sonnet 4.5 :

Imaginons un admin malveillant dans ton entreprise :

  • Il a accès physique aux serveurs
  • Il a accès au réseau (donc au serveur Tang)
  • Il clone un disque pendant la nuit
  • Il essaie de le monter sur sa propre machine pour extraire des données

Tang seul : ❌ Il réussit
TPM + Tang : ✅ Il échoue

Claude Sonnet 4.5


À noter que l'instance tang ne contient pas la passphrase et ne voit jamais passer la passphrase via son API.
Voici les explications que m'a données Claude Sonnet 4.5 :

Tang ne stocke pas la passphrase secrète de chiffrement LUKS. C'est justement tout l'intérêt de cette solution !

Voici comment ça fonctionne :

Le principe de Tang + Clevis

  1. Génération de clé dérivée : Clevis (le client) contacte le serveur Tang et récupère sa clé publique
  2. Chiffrement avec la clé de Tang : Clevis utilise cette clé publique pour chiffrer la passphrase LUKS
  3. Stockage local : La passphrase chiffrée est stockée localement dans l'en-tête LUKS du disque (pas sur le serveur Tang)
  4. Déchiffrement au boot :
  • La machine contacte Tang
  • Tang utilise sa clé privée pour aider à déchiffrer
  • La passphrase LUKS est reconstituée
  • Le disque est déverrouillé

Ce que Tang sait et ne sait pas

  • ❌ Tang ne connaît jamais votre passphrase LUKS
  • ❌ Tang ne stocke rien concernant vos clés
  • ✅ Tang fournit juste un service cryptographique (un oracle de déchiffrement)
  • ✅ C'est un serveur sans état (stateless)

C'est du chiffrement asymétrique avec un mécanisme appelé "network-bound disk encryption" : le disque ne peut être déchiffré que si la machine peut contacter le serveur Tang sur le réseau.

Claude Sonnet 4.5


Voici quelques ressources supplémentaires au sujet des techniques de déverrouillage automatique des volumes LUKS :

Journal du jeudi 13 novembre 2025 à 09:26 #golang, #JaiDécouvert

Dans mon activité professionnelle, #JaiDécouvert cerbos (https://github.com/cerbos/cerbos).

Cerbos is an authorization layer that evolves with your product. It enables you to define powerful, context-aware access control rules for your application resources in simple, intuitive YAML policies; managed and deployed via your Git-ops infrastructure. It provides highly available APIs to make simple requests to evaluate policies and make dynamic access decisions for your application.

source

Pour le moment je n'ai aucun avis sur cette technologie. Je ne l'ai pas encore étudié.

Ce projet est codé en Golang et a débuté en 2021.

Ma lutte contre mon affaiblissement cognitif #artificial-intelligence, #opinion, #JaiLu

#JaiLu cet excellent billet de Tristan Nitot qui traite du processus de prolétarisation : L'IA fait elle de nous des prolétaires ?.

Il rejoint totalement ce que je disais dans ma note : J'utilise les LLMs comme des amis experts et jamais comme des écrivains fantômes.

Cela pose la question de la façon dont on aborde l’IA : peut-on profiter de l’IA sans y laisser son intelligence ?

source

À cette question, ma réponse imparfaite est celle-ci : j'essaie d'utiliser, autant que possible, les IA générative de texte comme un ami expert d'un domaine. J'essaie de ne jamais lui faire faire mon travail à ma place.

J'essaie de résister à l'injonction néolibérale d'effectuer chaque tâche le plus rapidement possible au nom de la rentabilité immédiate. Pour cela, tous les jours, j'essaie de trouver un équilibre entre la vitesse et prendre le temps de comprendre, de maîtriser les concepts et d'exécuter les gestes techniques. C'est loin d'être facile !

Pour lutter contre mon affaiblissement cognitif, j'essaie depuis quelques semaines d'intégrer Anki dans mes habitudes quotidiennes.
Mon objectif : créer une carte-mémoire pour chaque tâche que je délègue à un LLM alors que je devrais pouvoir l'accomplir moi-même.
Pour le moment, je n'ai pas la discipline pour respecter cet objectif, mais j'y travaille.

J'ai bien conscience que ma pratique est hétérodoxe. J'observe autour de moi que la tendance est la course à l'automatisation du maximum de tâches par l'IA. Je souhaite rester un artisan.


#JaiLu aussi le billet "Prolétarisation" de Carnets de La Grange.

Journal du vendredi 07 novembre 2025 à 11:59 #OnMaPartagé

Alexandre m'a partagé l'article Wikipedia "Lavarand" :

Lavarand est un générateur de nombres aléatoires matériel créé par l'entreprise américaine Silicon Graphics.

Plus concrètement, il s'agit d'un dispositif utilisant des lampes à lave ce qui créé des motifs aléatoires, motifs qui sont photographiés afin d'en extraire des données pour alimenter un générateur de nombres pseudo-aléatoires.

Depuis 2017, l'entreprise américaine cloudflare maintient un système similaire de lampes à lave pour sécuriser le trafic Internet transitant par ses serveurs. Le mur de lampes à lave est accessible au grand public et l'entreprise incite les personnes extérieures à se placer devant pour créer de nouvelles variables alétoires. Les locaux de Londres et de Singapour utilisent des systèmes différents : respectivement des pendules et un compteur Geiger.

source

Je suis impressionné par cette technique, je la trouve très élégante.

Je me souviens avoir été confronté à ce problème de nombre aléatoire quand j'ai essayé, vers 1995, de programmer un effet Doom Fire en assembleur (époque avant l'accès à Internet).
Je m'étais cassé les dents pour obtenir un effet "aléatoire", c'était un vrai casse-tête !

Je viens de consulter la page "List of random number generators", je suis émerveillé par toutes ces techniques.

Journal du jeudi 06 novembre 2025 à 13:23 #philosophe, #NouveauMot, #JaiDécouvert

#JaiDécouvert le concept philosophique Homo faber.

En philosophie, la notion d'homo faber fait référence à l'Homme en tant qu'être susceptible de fabriquer des outils.

source

Journal du jeudi 06 novembre 2025 à 10:28 #Microsoft, #DevOps, #InfrastructureAsCode, #JaiDécouvert

Dans mon activité professionnelle, #JaiDécouvert Bicep (https://github.com/Azure/bicep) équivalent pour Microsoft Azure de Terraform et CloudFormation.


Je découvre aussi le format ARM Template JSON :

Bicep code is transpiled to standard ARM Template JSON files, which effectively treats the ARM Template as an Intermediate Language (IL).

source

Dans ce contexte, j'apprends qu'ARM signifie Azure Resource Manager.

Je comprends que le suffixe "rm" dans le nom du provider Terraform d'Azure terraform-provider-azurerm fait référence à "Resource Manager".

Setup Fedora CoreOS avec LUKS et TPM, non sécurisé contre le vol physique de serveur #CoreOS, #security, #linux, #admin-sys

Comme je l'ai dit dans cette précédente note, jusqu'il y a peu de temps, je ne m'étais jamais intéressé et j'avais même évité les technologies liées aux trusted computing.

Il y quelques jours, j'ai testé avec succès l'installation d'une Fedora CoreOS avec une clé de déchiffrement LUKS sauvegardée dans une puce TPM2 à l'aide de clevis.

Grâce à TPM, cette configuration évite de devoir saisir la clé de déchiffrement au moment du boot de l'OS.
Je trouve cette approche particulièrement pertinente sur une distribution CoreOS qui utilise zincati pour appliquer automatiquement les mises à jour de l'OS à des horaires définis (voir note à ce sujet).


Pour tester cette configuration, j'ai créé le playground install-coreos-iso-on-qemu-with-luks , qui me permet de tester localement l'installation dans une VM QEMU.
Pour émuler le TPM2, j'utilise swtpm et le BIOS UEFI Open source edk2-ovmf .

Dans ce test, j'ai choisi de créer et de chiffrer une partition pour stocker les données du dossier /var/, qui sur CoreOS est l'emplacement qui contient les données mutables (accessibles en écriture).

Voici la configuration butane de LUKS encryption avec les options TPM2 et clevis que j'ai utilisées (fichier complet) :

storage:
  disks:
    - device: /dev/nvme0n1
      wipe_table: false
      partitions:
        - number: 4
          label: root
          size_mib: 15000
          resize: true
        - number: 5
          label: var       <=== label
          size_mib: 0  # 0 = use all remaining space

  luks:
    - name: var            <=== label
      device: /dev/disk/by-partlabel/var
      wipe_volume: true
      key_file:
        inline: password
      clevis:
        tpm2: true
        
  filesystems:
    - path: /var
      device: /dev/mapper/var
      format: xfs
      wipe_filesystem: true
      label: var
      with_mount_unit: true

Je trouve le contenu de ce fichier de configuration assez simple et explicite.


J'ai ensuite créé un second playground install-coreos-iso-on-baremetal-with-luks.

L'installation automatique s'est déroulée sans problème sur un serveur baremetal.

J'ai testé la désactivation de TPM2 dans le BIOS : la console m'a alors demandé de saisir la clé manuellement. C'est plutôt pratique en cas de problème TPM, branchement du disque sur une autre machine…

La clé de chiffrement LUKS n'est pas stockée en clair dans le fichier ISO, il n'est donc pas nécessaire de sécuriser l'accès à ce fichier.


Attention, j'ai découvert que cette méthode n'est pas sécurisée en cas de vol physique du serveur !

Si un attaquant boot depuis un autre disque avec le même firmware et le même kernel, il pourra extraire en clair la clé LUKS stockée dans le TPM 🫣.

D'après mes recherches, la seule approche qui semble permettre à la fois la protection contre le vol physique et le reboot automatique serait d'utiliser clevis avec un serveur tang plutôt que le TPM.

Je compte tester cette configuration dans les prochaines semaines (depuis, cette note a été publiée : Setup Fedora CoreOS avec LUKS et Tang).

20 ans après avoir été traumatisé par le projet Palladium de Microsoft, je m'intéresse enfin au TPM2 #Microsoft, #security, #linux

Comme beaucoup de libristes, en 2002, j'ai été effrayé par le projet Palladium de Microsoft.

Palladium (NGSCB) était une initiative Microsoft annoncée en 2002 pour créer une plateforme de "trusted computing" basée sur du matériel sécurisé (une puce TPM dédiée) contrôlant strictement quels logiciels pouvaient s'exécuter et quels périphériques étaient autorisés à communiquer avec le système. L'objectif était de permettre à Microsoft de certifier cryptographiquement l'intégrité de toute la chaîne matérielle et logicielle, depuis le démarrage de l'ordinateur jusqu'aux applications en cours d'exécution.

On imaginait des scénarios concrets comme une carte son qui refuserait de capturer de l'audio depuis une sortie protégée par DRM, ou une carte graphique qui bloquerait la capture d'écran de contenu vidéo protégé.

À cette époque, Microsoft était en position hégémonique écrasante sur le marché des ordinateurs personnels : MacOS d'Apple représentaient moins de 3% des parts de marché.
Palladium représentait concrètement une forme de totalitarisme numérique sous contrôle total de Microsoft et des ayants droit.

Pour la communauté du libre, cela signifiait concrètement que ce système pourrait empêcher l'exécution de systèmes d'exploitation libres, bloquer l'accès aux périphériques sans drivers signés par Microsoft, et conduire à une génération d'ordinateurs où Linux serait techniquement banni ou très difficile à installer.

Heureusement, les critiques venues de toutes parts , combinées aux accusations de monopole et aux risques antitrust, ont contraint Microsoft à faire marche arrière. Cela a abouti à la situation actuelle où le TPM est davantage orienté vers la sécurité que vers le DRM et la restriction des libertés des utilisateurs.

Cet épisode a eu des conséquences durables pour moi : depuis, dès que j'entendais parler de puce de sécurité ou de TPM, j'avais immédiatement une réaction de rejet, parce que cela évoquait pour moi vendor lock-in, restrictions et contrôle par Microsoft. Je n'ai jamais cherché à en savoir plus.

C'est seulement en septembre 2025, lors de mon exploration du filesystem fs-verity, que j'ai découvert que les fonctionnalités du TPM2 sont en réalité très intéressantes et peuvent servir des objectifs de sécurité légitimes, très bien supportées par Linux.

Journal du samedi 25 octobre 2025 à 10:37 #iteration, #CoreOS, #projet, #linux, #security

Mon objectif du weekend est d'avancer sur le Projet 34 - "Déployer un cluster k3s et Kubevirt sous CoreOS dans mon Homelab".

Je veux apprendre à configurer LUKS encryption sous CoreOS avec un démarrage automatique basé sur TPM2 via clevis.

Je veux aussi m'assurer qu'en cas de problème, je peux toujours monter la partition chiffrée en saisissant manuellement la clé secrète.

J'ai découvert les types "unknown" et "never" en TypeScript #typescript, #javascript, #JaiDécouvert, #JaimeraisUnJour

En TypeScript, dans mon projet professionnel, #JaiDécouvert le type unknown qui ressemble à any mais qui est différent.

Exemple (produit par Claude Sonnet 4.5) avec any :

let value: any;
value.foo.bar(); // No error, even if it crashes at runtime
value.trim(); // No error, even if value is a number

Exemple avec unknown :

let value: unknown;
value.trim(); // Error: Object is of type 'unknown'

// You must narrow the type first
if (typeof value === 'string') {
  value.trim(); // OK, TypeScript knows it's a string
}

unknown a été introduit dans la version 3.0 de TypeScript en 2018 : Announcing TypeScript 3.0 - The unknown type.

J'ai trouvé les réponses à cette question StackOverflow intéressantes : 'unknown' vs. 'any'.

C'est peut-être parce que je ne suis pas habitué à la documentation de TypeScript , mais j'ai l'impression que la fonctionnalité unknown n'est pas correctement documentée. Par exemple, je suis surpris de trouver presque rien à son sujet dans la page Everyday-types , ni dans les chapitres "Reference" :

Et rien non plus dans les tutoriels.

Au passage, j'ai aussi découvert le type never.


#JaimeraisUnJour prendre le temps de parcourir la documentation de TypeScript de manière exhaustive. Jusqu'à présent, je n'en ai jamais eu réellement besoin, car je n'ai jamais contribué à de projet écrit en TypeScript. Mais maintenant, cela devient une nécessité pour mon projet professionnel.

Convergence vers Bootc #fedora, #linux, #distribution-linux, #gnome

Cette note fait partie de la série de notes : "J'ai étudié et testé CoreOS et je suis tombé dans un rabbit hole 🙈".

Note précédente : "Support OCI de CoreOS (image pull & updates)".


Colin Walters, le principal développeur de libostree a initié le projet bootc en mars 2021. J'ai découvert le projet bootc en début d'année et lisant des articles liés à systemd.

La vision de bootc est assez simple : rendre la création d'images de système d'exploitation aussi simple que la création d'images de conteneurs d'applications tout en utilisant les mêmes outils. Pour avoir un peu de contexte historique, je conseille l'article lwn de juin 2024 : Making containers bootable for fun and profit

Les images bootc utilisent la même technologie de stockage que les images des container classique : OCI.

D'après ce que j'ai compris, ce type d'image bootc ne porte pas nom officiellle, elles sont nommés aussi bien "bootc image", que "bootable container image" ou "bootable OCI image".

En janvier 2025, Red Hat a transféré le projet bootc à la CNCF. Le but est de permettre à toutes les distributions de l'adopter comme standard, indépendamment de Red Hat.

Parmis les distributions qui ont adopté bootc, trois retiennent mon attention :


Au moment où j'écris ces lignes, je pense migrer d'ici quelques mois ma workstation vers une distribution Desktop bootc, probablement Bluefin, qui est déjà disponible, ou Fedora Silverblue, une fois que son support bootc sera finalisé.

J'aurai donc certainement l'occasion de tester en pratique comment créer des images bootc personnalisées.

Voici diverses ressources que j'ai trouvées concernant le support bootc pour Fedora Silverblue :

Je compte aussi tester bootc et tout particulièrement Bluefin dans le cadre de mon "Projet 26 - "Expérimentation de migration de deux utilisateurs grand public vers des laptops sous Fedora"".

Support OCI de CoreOS (image pull & updates) #CoreOS, #docker, #distribution-linux, #linux, #DevOps, #JaiDécouvert

Cette note fait partie de la série de notes : "J'ai étudié et testé CoreOS et je suis tombé dans un rabbit hole 🙈".

Note précédente : "L'utilisation de OSTree par Flatpak".


Le format Open Container Initiative (Docker image) utilise le media type application/vnd.oci.image.layer.v1.tar+gzip et se compose de métadonnées au format JSON accompagnées de plusieurs archives tar.gz. Ce format est beaucoup moins optimisé pour le stockage et le transfert que celui de libostree, qui utilise un système de déduplication basé sur les objets et des deltas binaires (pour en savoir plus, voir la note "2014-2018 approche alternative avec Atomic Project").

La déduplication OCI s'effectue au niveau des layers complets. Par exemple, si je build localement une image à partir du Dockerfile suivant :

# image frontend
FROM fedora:39            # layer 1
RUN dnf install -y pkg1   # layer 2 - 50Mb
COPY app.js /app/         # layer 3

Puis une seconde image avec ce Dockerfile :

# image backend
FROM fedora:39                 # layer 1
RUN dnf install -y pkg1 pkg2   # layer 4 - 100 Mb
COPY app.js /app/              # layer 3

Les layers 2 et 4 sont considérés comme différents car leurs contenus diffèrent (commandes RUN différentes). Les fichiers du package pkg1 sont donc stockés deux fois. La taille totale sur disque et lors du transfert est de 150 MB (au lieu de 100 MB avec une déduplication au niveau fichier).

Malgré cette limitation, depuis la version 42 , Fedora CoreOS utilise le support OCI de OSTree pour télécharger les mises à jour système. Ce changement constitue la première itération vers la migration de CoreOS vers bootc.

Le format OCI semble privilégié à libostree comme format d'échange car son écosystème est plus populaire : utilisation par Docker, Kubernetes, podman, disponibilité sur Docker Hub, et maîtrise généralisée du format Dockerfile.

Depuis la version 4.0.0 , podman supporte le format de compression zstd:chunked , basé sur les zstd skippable frames . Ce format permet une déduplication plus fine en découpant les layers en chunks, améliorant ainsi l'efficacité des téléchargements différentiels, bien que restant inférieur à des capacités de libostree. À noter que seul le registry quay supporte actuellement ce format — Docker Hub ne le prend pas encore en charge.

En explorant ce sujet de déduplication (qui permet de réduire la taille des données à télécharger lors des mises à jour), #JaiDécouvert bsdiff, bspatch, Rolling hash (je l'avais déjà croisé).


Note suivante : "Convergence vers Bootc".

L'utilisation de OSTree par Flatpak #distribution-linux, #fedora, #gnome

Cette note fait partie de la série de notes : "J'ai étudié et testé CoreOS et je suis tombé dans un rabbit hole 🙈".

Note précédente : "composefs, un filesystem spécialement créé pour les besoins des distributions atomic"


En étudiant libostree, j'ai découvert que Flatpak est construit sur OSTree depuis sa création : voir page Flatpak documentation - Under the Hood.

Flatpak utilise la fonctionnalité pull d'OSTree pour télécharger l'intégralité des applications depuis un repository OSTree, ou des deltas pour les mises à jour. Depuis la version 0.6.0 de 2016, Flatpak supporte aussi le téléchargement au format OCI.

Voici un exemple de repository Flatpak configuré sur mon workspace :

$ flatpak remotes -d

Name    Title                    URL                                    Collection ID Subset Filter Priority Options    Com… Descript… Homepage             Icon
fedora  Fedora Flatpaks          oci+https://registry.fedoraproject.org -             -      -      1        system,oci -    -         -                    -
flathub Fedora Flathub Selection https://dl.flathub.org/repo/           -             -      -      1        system     Sel… Selected… https://flathub.org/ https://dl.flathub.org/repo/logo.svg
flathub Flathub                  https://dl.flathub.org/repo/           -             -      -      1        user       Cen… Central … https://flathub.org/ https://dl.flathub.org/repo/logo.svg

On peut voir que Flathub est un serveur libostree et le registry registry.fedoraproject.org utilise le format OCI.

Sans entrer dans les détails (ce serait trop long pour cette note), libostree est la raison pour laquelle Flatpak est plus performant que Snap basé sur squashfs.
Selon Claude.ia, Flatpak offre par rapport à Snap : un démarrage des applications 2 à 3 fois plus rapide, 60-80% de bande passante en moins sur les mises à jour, et 30-40% d'espace disque économisé.


Note suivante : "Support OCI de CoreOS (image pull & updates)".

composefs, un filesystem spécialement créé pour les besoins des distributions atomic #CoreOS, #linux, #distribution-linux

Cette note fait partie de la série de notes : "J'ai étudié et testé CoreOS et je suis tombé dans un rabbit hole 🙈".

Note précédente : "Quelques outils CoreOS : coreos-installer, graphe de migration et zincati".


En 2021, Alexander Larsson a initié composefs, un nouveau filesystem. Pour faire simple, composefs permet de monter un filesystem depuis un checkout libostree.

composefs est un filesystem de type "stacking filesystem" qui combine plusieurs technologies :

  • EROFS : fournit la couche read-only et l'efficacité de stockage
  • overlayfs : gère la superposition de layers
  • fs-verity : assure la vérification d'intégrité des fichiers à la volée

Avec libostree seul (sans composefs), les checkout s'appuient sur des hardlinks vers un store central. Cette approche économise de l'espace disque, mais présente deux limitations :

  1. L'utilisateur root peut modifier les fichiers et corrompre le store partagé
  2. Il n'y a pas de vérification d'intégrité lors de l'accès aux fichiers

Grâce à EROFS, un filesystem read-only, la structure de fichier checkout devient immuable, ces fichiers ne sont plus des hardlink.

composefs a l'avantage de pouvoir utiliser différents filesystèmes comme couche de stockage : ext4, XFS, btrfs, etc.

Comme l'explique Alexander Larsson dans ce post de 2022, le second objectif de composefs est d'adresser une limitation de sécurité d'OSTree identifiée par Lennart Poettering : les fichiers gérés par libostree ne sont vérifiés qu'au moment de leur téléchargement, pas lors de leur utilisation.

Grâce à fs-verity (une fonctionnalité du kernel Linux), composefs permet la vérification cryptographique des fichiers à chaque accès (runtime verification). Cette approche peut détecter toute modification ou corruption au moment de l'utilisation du fichier. Je précise que je maîtrise assez mal cette partie sécurité.

Pour approfondir le sujet composefs, je vous conseille l'article lwn "Composefs for integrity protection and data sharing " de décembre 2022 ou encore tous les billets de Alexander Larsson au sujet de composefs, ainsi que ce "OSTree and composefs tutorial" qui m'a aidé à mieux comprendre par la pratique.

composefs a été intégré dans la version 41 de Fedora CoreOS et la version 42 de Fedora Silverblue. Voici une vérification de la présence de composefs sous CoreOS :

stephane@stephane-coreos:~$ ostree --version
libostree:
Version: '2025.4'
Git: 99a03a7bb8caa774668222a0caace3b7e734042e
Features:
- inode64
- initial-var
- libcurl
- libsoup3
- gpgme
- composefs   <==== ici
- ex-fsverity
- libarchive
- selinux
- openssl
- sign-ed25519
- sign-spki
- libmount
- systemd
- release
- p2p

stephane@stephane-coreos:~$ mount | grep -i composefs
composefs on / type overlay (ro,relatime,seclabel,lowerdir+=/run/ostree/.private/cfsroot-lower,datadir+=/sysroot/ostree/repo/objects,redirect_dir=on,metacopy=on)

Note suivante : "L'utilisation de OSTree par Flatpak".

Quelques outils CoreOS : coreos-installer, graphe de migration et zincati #CoreOS, #fedora, #linux, #admin-sys, #DevOps, #Kubernetes

Cette note fait partie de la série de notes : "J'ai étudié et testé CoreOS et je suis tombé dans un rabbit hole 🙈".

Note précédente : "Fusion de CoreOS et Atomic Project en 2018".


coreos-installer

L'outil coreos-installer est un composant essentiel de Fedora CoreOS. Il propose différentes méthodes pour installer Fedora CoreOS.

La commande coreos-installer download permet de télécharger tout type de version de CoreOS, sous différents formats, par exemple iso, raw, qemu, cloud image, etc (toutes celles présentes dans la page download).

Ensuite, la commande coreos-installer install permet d'installer la version téléchargée vers un disque. Cette commande est par exemple disponible à la fin du boot d'une image ISO. Contrairement à Fedora Silverblue qui propose d'installer la distribution avec Anaconda, l'installation de CoreOS s'effectue en cli via coreos-installer install.

Ensuite, la commande coreos-installer install permet d'installer la version téléchargée sur un disque. Cette commande est notamment accessible après le démarrage d'une image ISO. Contrairement à Fedora Silverblue qui utilise l'installateur graphique Anaconda, CoreOS s'installe exclusivement en cli via coreos-installer install.

Toutefois, coreos-installer permet de préparer une installation automatique. La commande coreos-installer iso customize modifie une image ISO existante pour y intégrer directement une configuration ignition, rendant l'installation entièrement automatisée au démarrage.

Voici un exemple dans mon playground : atomic-os-playground/create-coreos-custom-iso.sh.

coreos-installer pxe permet aussi d'effectuer une configuration automatique par réseau, via PXE, mais je ne l'ai pas testé.

Graphe de migration de versions

Lors de mes tests d'upgrade de CoreOS à partir d'une ancienne release (environ n-10), j'ai constaté que la transition vers la dernière version ne se faisait pas directement mais nécessitait le passage par des versions intermédiaires.

J'ai découvert que CoreOS maintient un graphe qui définit le parcours d'upgrade requis. Certaines versions intermédiaires doivent être installées pour gérer des breaking changes, comme la migration de configurations.

zincati

Un autre composant important de Fedora CoreOS est zincati, le service responsable de l'exécution des mises à jour automatiques.

zincati décide d'effectuer les mises à jour en fonction du seuil de prudence de déploiement (rollout_wariness) et de la stratégie de mise à jour : immediate ou periodic (plage horaire définie dans la semaine).

CoreOS utilisant par défaut la stratégie immediate, zincati détecte automatiquement les nouvelles releases dès le premier démarrage et lance immédiatement leur téléchargement, suivi d'un redémarrage.

Le téléchargement par deltas rend l'upgrade vers la dernière release très rapide.

zincati permet également de coordonner les mises à jour de plusieurs serveurs, fonctionnalité particulièrement utile dans le contexte d'un cluster Kubernetes. Je n'ai pas encore testé cette fonctionnalité.


Note suivante : "composefs, un filesystem spécialement créé pour les besoins des distributions atomic".

Fusion de CoreOS et Atomic Project en 2018 #CoreOS, #linux, #fedora

Cette note fait partie de la série de notes : "J'ai étudié et testé CoreOS et je suis tombé dans un rabbit hole 🙈".

Note précédente : "2014-2018 approche alternative avec Atomic Project".


Suite au rachat de la société CoreOS par Red Hat en 2018, les projets CoreOS Container Linux et Fedora Atomic Host ont fusionné en juillet 2019 pour donner Fedora CoreOS.

D'après mon analyse, mise à part ignition, le projet Fedora CoreOS est construit sur les bases de Fedora Atomic Host et n'a gardé de CoreOS Container Linux que le nom "CoreOS".

Cette nouvelle distribution Fedora CoreOS reste atomic et immutable comme l'ancien CoreOS Container Linux, mais utilise désormais rpm-ostree et OSTree (au lieu du système dual partition A/B), et permet le package layering si nécessaire. La philosophie "100% conteneurs" reste encouragée, mais n'est plus une contrainte absolue.

Voici une chronologie sur l'histoire de CoreOS que m'a proposée Claude Sonnet 4.5 :

2013-2017: CoreOS Container Linux
           ├─ Atomic ✓ (dual partition)
           ├─ Immutable ✓
           └─ Package layering ✗

2014-2018: Fedora/RHEL Atomic Host
           ├─ Atomic ✓ (OSTree)
           ├─ Immutable ✓
           └─ Package layering ✓ (rpm-ostree)

2018:      Rachat CoreOS par Red Hat

2019+:     Fedora CoreOS (fusion des deux)
           ├─ Atomic ✓ (OSTree)
           ├─ Immutable ✓
           ├─ Package layering ✓ (possible mais découragé)
           └─ Philosophie: conteneurs first, mais flexible

Note suivante : "Quelques outils CoreOS : coreos-installer, graphe de migration et zincati".

Je fais mon retour dans l'écosystème React, j'ai découvert Jotai et Zustand #ReactJS, #WebDev, #svelte, #javascript, #JaiDécouvert, #JaiLu

Dans le code source de mon projet professionnel, #JaiDécouvert la librairie ReactJS nommée Jotai (https://jotai.org).

Les atom de Jotai ressemblent aux fonctionnalités Svelte Store. Jotai permet entre autres d'éviter de faire du props drilling.

Pour en savoir plus sur l'intérêt de Jotai versus "React context (useContext + useState)", je vous conseille la lecture d'introduction de la page Comparison de la documentation Jotai. J'ai trouvé la section "Usage difference" très simple à comprendre.

Cette découverte est une bonne surprise pour moi, car les atom de Jotai reproduisent l'élégance syntaxique des Store de Svelte, ce qui améliore mon confort de développement en ReactJS. #JaiLu ce thread Hacker News en lien avec le sujet : "I like Svelte more than React (it's store management)".

Je tiens toutefois à préciser que si Jotai améliore significativement mon expérience de développeur (DX) avec ReactJS, cela reste une solution de gestion d'état au sein du runtime ReactJS. En comparaison, le compilateur Svelte génère du code optimisé natif qui reste intrinsèquement plus performant à l'exécution.

Exemple Svelte :

import { writable, derived } from 'svelte/store';

const count = writable(0);
const doubled = derived(count, $count => $count * 2);

// Usage dans component
$count // auto-subscription

Exemple ReactJS basé sur Jotai :

import { atom } from 'jotai';

const countAtom = atom(0);
const doubledAtom = atom(get => get(countAtom) * 2);

// Usage dans component
const [count] = useAtom(countAtom);

J'ai lu la page "Comparison" de Jotai pour mieux comprendre la place qu'a Jotai dans l'écosystème ReactJS.

#JaiDécouvert deux autres librairies développées par la même personne, Daishi Kato : Zustand et Valtio. D'après ce que j'ai compris, Daishi a développé ces librairies dans cet ordre :

J'ai aussi découvert Recoil développé par Facebook, mais d'après son entête GitHub celle-ci semble abandonnée. Une migration de Recoil vers Jotai semble être conseillée.

J'aime beaucoup comment Daishi Kato choisit le nom de ses librairies, la méthode est plutôt simple 🙂 :

Jotai means "state" in Japanese. Zustand means "state" in German.

source

Comme mentionné plus haut, Jotai ressemble à Recoil alors que Zustand ressemble à Redux :

Analogy

Jotai is like Recoil. Zustand is like Redux.

...

How to structure state

Jotai state consists of atoms (i.e. bottom-up). Zustand state is one object (i.e. top-down).

source


Même en lisant la documentation Comparison, j'ai eu de grandes difficulté à comprendre quand préférer Zustand à Jotai.
En lisant la documentation, Jotai me semble toujours plus simple à utiliser que Zustand.

Avec l'aide de Claude Sonnet 4.5, je pense avoir compris quand préférer Zustand à Jotai.

Exemple Zustand

Dans l'exemple Zustand suivant, la fonction addToCart modifie plusieurs parties du state useCartStore en une seule transaction :

import { create } from 'zustand'

const useCartStore = create((set) => ({  
	user: null,  
	cart: [],  
	notifications: [],  
    
	addToCart: (product) => set((state) => {  
		return {  
		    cart: [...state.cart, product],  
		    notifications: (  
				state.user
					? [...state.notifications, { type: 'cart_updated' }]
					: state.notifications
			)  
		};
    };  
}));

Et voici un exemple d'utilisation de addToCart dans un composant :

function ProductCard({ product }) {
	// Sélectionner uniquement l'action addToCart
	const addToCart = useCartStore((state) => state.addToCart);
  
	return (
	    <div>
		    <h3>{product.name}</h3>
			<p>{product.price}€</p>
			<button onClick={() => addToCart(product)}>
			    Ajouter au panier
		    </button>
		</div>
	);
}

Exemple Jotai

Voici une implémentation équivalente basée sur Jotai :

import { atom } from 'jotai';

const userAtom = atom(null);
const cartAtom = atom([]);
const notificationsAtom = atom([]);

export const addToCartAtom = atom(
	null,
	(get, set, product) => {
		const user = get(userAtom);
		const cart = get(cartAtom);
		const notifications = get(notificationsAtom);
    
		set(cartAtom, [...cart, product]);
    
		if (user) {
			set(notificationsAtom, [...notifications, { type: 'cart_updated' }]);
		}
	}
);

Et voici un exemple d'utilisation de useToCartAtom dans un composant :

import { useSetAtom } from 'jotai';
import { addToCartAtom } from 'addToCartAtom';

function ProductCard({ product }) {
	// Récupérer uniquement l'action (pas la valeur)
	const addToCart = useSetAtom(addToCartAtom);
  
	return (
		<div>
		    <h3>{product.name}</h3>
		    <p>{product.price}€</p>
		    <button onClick={() => addToCart(product)}>
			    Ajouter au panier
			</button>
	    </div>
	);
}

Ces deux exemples montrent que Zustand est plus élégant et probablement plus performant que Jotai pour gérer des actions qui conditionnent ou modifient plusieurs parties du state simultanément.


#JaiLu le thread SubReddit ReactJS "What do you use for global state management? " et j'ai remarqué que Zustand semble plutôt populaire.

En rédigeant cette note, j'ai découvert Valtio qui semble être une alternative à MobX. Je prévois d'étudier ces deux librairies dans une future note.

Journal du dimanche 19 octobre 2025 à 11:20 #ReactJS, #JaiDécouvert

Dans l'historique de mon projet professionnel, #JaiDécouvert immer. J'ai constaté que Jotai propose une extension permettant d'utiliser immer. Pour le moment, je n'ai aucune idée de son intérêt, je n'ai pas pris le temps d'étudier ce sujet.

Journal du dimanche 19 octobre 2025 à 11:16 #ReactJS, #JaiDécouvert

Ici dans la documentation Jotai, #JaiDécouvert Waku. Je n'ai pas pris le temps de l'étudier.

Journal du samedi 18 octobre 2025 à 12:18 #ReactJS, #WebDev, #JaiDécouvert

En étudiant la librairie Jotai, #JaiDécouvert le terme "props drilling" :

Passing props is a great way to explicitly pipe data through your UI tree to the components that use it.

But passing props can become verbose and inconvenient when you need to pass some prop deeply through the tree, or if many components need the same prop. The nearest common ancestor could be far removed from the components that need data, and lifting state up that high can lead to a situation called “prop drilling”.

source

Le terme props drilling est très présent dans le SubReddit ReactJS : https://old.reddit.com/r/reactjs/search?q=drilling&restrict_sr=on&include_over_18=on.

Vous êtes sur la première page | [ Page suivante (3908) >> ]