Notifications ChromeOS natives pour CLI : Le Guide Complet via D-Bus, Crostini & cros-notificationd

Publié par · juin 12, 2026 · Calcul du temps...

Le Problème : Des Notifications CLI Invisibles sur ChromeOS

Les assistants IA en ligne de commande (CLI) comme OpenCode, Antigravity CLI ou Claude Code sont devenus des outils indispensables. Mais sur ChromeOS via Crostini (le conteneur Linux), un problème récurrent se pose : les notifications notify-send sont envoyées dans le vide et jamais visibles dans le panneau de notification ChromeOS.

Vous lancez une tâche longue (build, analyse, déploiement), vous passez sur un autre bureau virtuel, et quand la tâche se termine... rien. Pas de notification. Vous devez retourner manuellement sur votre terminal pour vérifier l'état.

Pourquoi les Notifications CLI ne Marchent Pas par Défaut

Sur une installation Linux classique, notify-send envoie une notification via D-Bus au daemon de notification (comme Dunst, Mako, ou GNOME Shell). ChromeOS utilise une architecture différente :

CLI → notify-send → D-Bus → ??? (rien d'affiché)

Le problème vient de l'architecture Crostini elle-même. ChromeOS ne fait pas tourner un daemon de notification visible standard. À la place, le daemon Garcon (Chromium OS Garcon Bridge) intercepte les notifications D-Bus comme solution de repli. Mais Garcon ne les forwarde pas à l'interface utilisateur ChromeOS. Les notifications sont acceptées sur D-Bus, retournent un code de succès... et sont immédiatement jetées.


Notre Parcours de Recherche

Première Approche (Échec) : Dunst & paplay

Notre première idée a été d'installer un daemon de notification standard :

sudo apt install dunst libnotify-bin

Résultat : Un panneau rouge intrusif apparaît (interface dunst), pas intégré du tout à ChromeOS. De plus, dunst.service entre en conflit avec Garcon sur le nom D-Bus org.freedesktop.Notifications. Dunst est un panneau "maison" qui ne s'intègre pas au look natif.

On a aussi essayé paplay pour ajouter des sons différenciés :

paplay /usr/share/sounds/freedesktop/stereo/complete.oga

Problème : Le son joue dans le conteneur Linux, pas dans ChromeOS. Si l'utilisateur est sur un autre bureau, il n'entend rien.

Deuxième Approche (Échec) : notify-send sans daemon

En supprimant Dunst, on a cru que Garcon forwardait les notifications à ChromeOS. Le notify-send retournait un exit code 0. Pourtant, rien ne s'affichait.

Cause racine : Garcon possède org.freedesktop.Notifications sur D-Bus et implémente l'interface de notification (GetServerInformation retourne même "dunst" en raison du code interne partagé). Mais son implémentation est un puits noir : il accepte les notifications mais ne les affiche ni ne les forwarde.


La Solution : cros-notificationd

L'Architecture Officielle ChromeOS

Après des recherches approfondies dans le code source ChromiumOS et la documentation Crostini, la solution officielle est apparue :

notify-send → D-Bus → org.freedesktop.Notifications → notificationd → Wayland → Sommelier → ChromeOS

notificationd est un daemon officiel Google qui :

  1. Écoute sur org.freedesktop.Notifications via D-Bus
  2. Se connecte au Wayland compositor (Sommelier) via le protocole shell
  3. Transmet les notifications à ChromeOS qui les affiche dans le panneau natif (bas droite, près de l'horloge)

Pourquoi notificationd n'était Pas Actif

Le package cros-notificationd (version 0.3, ~1 Ko) est un package officiel du dépôt Google Crostini. Il installe :

  1. Un fichier de service D-Bus : /usr/share/dbus-1/services/org.freedesktop.Notifications.service
  2. Une unité systemd user : cros-notificationd.service

Mais ce package n'est pas installé par défaut dans les conteneurs Crostini Debian 13 (Trixie). Résultat : Garcon prend le nom D-Bus comme fallback et les notifications disparaissent.

Comment nous Avons Résolu le Problème

Étape 1 : Supprimer les daemons concurrents

Dunst entre en conflit direct avec notificationd :

sudo apt remove dunst
systemctl --user daemon-reload

Étape 2 : Installer cros-notificationd

sudo apt install cros-notificationd

Ce package active le service D-Bus qui démarre notificationd à la demande (demand-activation).

Étape 3 : Redémarrer le conteneur

Un simple redémarrage du terminal Linux suffit. Après redémarrage :

  • notificationd réclame org.freedesktop.Notifications sur D-Bus
  • Garcon échoue silencieusement à le réclamer (notificationd gagne)
  • Tous les appels notify-send sont maintenant forwardés à ChromeOS

Architecture Finale : Notifications Actionnables

Le Plugin OpenCode

Nous avons créé un plugin OpenCode qui s'interrompt au cycle de vie de l'agent :

// ~/.config/opencode/plugins/notification.js
export const NotificationPlugin = async ({ $ }) => {
return {
event: async ({ event }) => {
const icon = `${process.env.HOME}/.config/opencode/icon.png`
const helper = `${process.env.HOME}/.opencode/bin/helper-notify.sh`
if (event.type === "permission.asked") {
await ``${helper} ${icon} critical "OpenCode" "🔔 Action requise"``
}
if (event.type === "session.idle") {
await ``${helper} ${icon} normal "OpenCode" "✅ Tâche terminée"``
}
if (event.type === "session.error") {
await ``${helper} ${icon} critical "OpenCode" "❌ Erreur détectée"``
}
},
}
}

Le Script Helper (Action Clic → Focus Terminal)

Pour rendre les notifications actionnables (clic = focus terminal), nous utilisons la fonctionnalité --action de notify-send :

#!/bin/bash
# ~/.opencode/bin/helper-notify.sh
ICON="$1"
URGENCY="$2"
TITLE="$3"
MESSAGE="$4"

ACTION=$(notify-send -i "$ICON" -u "$URGENCY" -A "default=Focus" -t 0 "$TITLE" "$MESSAGE")
if [ "$ACTION" = "default" ]; then
wmctrl -a "$TITLE" 2>/dev/null || wmctrl -R "Terminal" 2>/dev/null || true
fi

Points clés :

  • -A "default=Focus" : rend la notification cliquable avec l'action par défaut "Focus"
  • -t 0 : la notification ne se cache jamais toute seule (expire au clic uniquement)
  • wmctrl : tente de focus la fenêtre du terminal (X11 via XWayland)
  • Sur ChromeOS, le clic sur la notification déclenche aussi le comportement natif de ChromeOS (focus automatique du conteneur)

Icône OpenCode

Pour une intégration parfaite, nous avons récupéré le logo officiel OpenCode (apple-touch-icon 180×180) :

curl -sL -o ~/.config/opencode/icon.png https://opencode.ai/apple-touch-icon-v3.png

Leçons Apprises et Bonnes Pratiques

1. Ne JAMAIS Tuer Garcon

Règle absolue : Garcon est le daemon central d'intégration ChromeOS. Il gère :

  • Le lancement des applications Linux depuis le lanceur ChromeOS
  • Les types MIME et associations de fichiers
  • Le proxy SFTP (partage de fichiers ChromeOS ↔ conteneur)
  • Les mises à jour des packages Google Crostini

Si vous stoppez Garcon (systemctl --user stop cros-garcon.service), tout le conteneur s'effondre : les MCP serveurs plantent, le terminal se déconnecte, Chromium headless crashe. Un simple reboot du conteneur suffit pour que notificationd prenne le relais.

2. Vérifier le Daemon de Notification

Après installation, confirmez que notificationd gère les notifications :

# Vérifier qui possède org.freedesktop.Notifications
dbus-send --session --dest=org.freedesktop.DBus --type=method_call --print-reply \
/org/freedesktop/DBus org.freedesktop.DBus.GetNameOwner \
string:org.freedesktop.Notifications

# Vérifier que les actions sont supportées
dbus-send --session --dest=org.freedesktop.Notifications --type=method_call --print-reply \
/org/freedesktop/Notifications org.freedesktop.Notifications.GetCapabilities

La sortie doit montrer :

array [
string "actions"
string "body"
]

3. Utilisez les Notifications Actionnables

Utilisez -A "default=ActionLabel" pour rendre les notifications cliquables. "default" est le mot-clé spécial qui correspond au clic sur le corps de la notification.

4. Gestion des Sons

N'utilisez PAS paplay ou d'autres outils audio dans le conteneur. ChromeOS joue son propre son de notification pour les notifications natives. C'est plus propre, moins intrusif, et parfaitement intégré.

5. Multiples Bureaux Virtuels

Sur ChromeOS, les notifications apparaissent sur le bureau actif et restent dans le panneau de notification (en bas à droite) même après avoir changé de bureau virtuel. L'utilisateur peut cliquer dessus à tout moment pour revenir sur le terminal.


Dépendances et Paquets

PaquetRôleTaille
cros-notificationdPont D-Bus → Wayland → ChromeOS1 Ko
libnotify-binClient notify-sendPré-installé
sound-theme-freedesktopSons système (optionnel)200 Ko
wmctrlFocus fenêtre X11 (action clic)100 Ko

Conclusion

Les notifications ChromeOS natives pour outils CLI sont non seulement possibles mais élégantes. La clé était le package officiel cros-notificationd, absent par défaut du conteneur Debian 13 Trixie.

En suivant cette architecture :

  • ✅ Notifications visibles dans le panneau ChromeOS (bas droite)
  • ✅ Icône personnalisée (OpenCode)
  • ✅ Son système ChromeOS (pas de bruit parasites)
  • ✅ Clic → focus terminal (quand possible)
  • ✅ Auto-dismiss au clic (comportement natif)
  • ✅ Trois niveaux d'urgence (normal, critical)
  • ✅ Fonctionne sur tous les bureaux virtuels

Le code source complet des plugins est disponible dans ~/.config/opencode/plugins/notification.js et fonctionne avec OpenCode, Antigravity CLI, et tout outil supportant notify-send.

Partager :

Architecte cloud & veille technologique — IA, DevOps, FinOps, Agentic Engineering.