Communitygithub.com

iwishwp/AgentOS

Opère le bureau AgentOS (niri/Wayland) : gestion des fenêtres et espaces de travail, accessibilité des applications GUI, automatisation du navigateur, artefacts fichiers, notifications et présentations. Utilisable par tout framework d'agent monté avec les huit extensions MCP d'AgentOS (niri/desktop/system/files/session/a11y/browser/cred). À utiliser lorsqu'il s'agit de manipuler des applications/fenêtres/fichiers/notifications sur le bureau de l'utilisateur.

Qu'est-ce que AgentOS ?

AgentOS est un ensemble complet d'outils pour l'automatisation du bureau Linux via les protocoles MCP et Wayland, conçu pour les agents IA tels que Claude Code, Cursor, Codex, ou Goose. Il expose huit extensions MCP (niri, desktop, system, files, session, a11y, browser, cred) qui couvrent l'intégralité des capacités : gestion des fenêtres et espaces de travail, contrôle des applications via l'arbre d'accessibilité AT-SPI2 (L1), automatisation de navigateur avec un Chromium headless dédié (L2), lecture/écriture de fichiers dans un bac à sable, notifications de bureau, requêtes de confirmation utilisateur, et gestion sécurisée des identifiants par références. L'architecture suit un modèle à quatre niveaux de priorité décroissante : L0 (système) le plus fiable, L1 (accessibilité), L2 (navigateur), et L3 (visuel/saisie) en dernier recours. Le système est testé en conditions réelles sur Fedora avec niri Wayland, et chaque extension MCP doit être montée via un script de démarrage dédié qui découvre automatiquement le socket IPC niri et complète l'environnement Wayland/dbus. AgentOS est particulièrement utile pour les scénarios où un agent doit interagir avec le bureau de l'utilisateur sans perturber son activité, en utilisant l'accessibilité sans focus ou un session `aquarium` isolée.

Compatible avec✓Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/iwishwp/AgentOS/tree/HEAD/skills/agentos-desktop

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Manuel d'opération du bureau AgentOS (universel pour tout agent)

Ce manuel est autonome : tant que votre framework peut monter un serveur MCP stdio (Goose / Claude Code / Z Code / Cursor, etc.), montez-le conformément au §1 et vous obtiendrez toutes les capacités ci-dessous. Toutes les entrées sont testées sur machine réelle (Fedora + niri Wayland, preuves de bout en bout datant d'octobre 2026 dans le dépôt sous docs/capabilities.md).

0. Modèle mental : quatre niveaux de capacité, par priorité décroissante

  1. L0 Couche système — fenêtres/espaces de travail/lancement/fichiers/notifications/presse-papier (extensions niri/desktop/system/files) : le plus stable, à utiliser en priorité ;
  2. L1 Arbre d'accessibilité — clics par nom/lecture et écriture de texte dans les applications GUI (extension a11y, AT-SPI2) : sans besoin de focus, ne dérange pas l'utilisateur, testé avec succès sur GTK3/GTK4/Qt (l'interrupteur global de Qt et toolkit-accessibility de Chromium sont activés par défaut système depuis le 18 octobre 2026) ; l'arbre Chromium est lisible et la saisie de texte possible (les clics sur les pages passent par L2) ; Java non installé (voir annexe B de capabilities.md) ; les applications purement X11 (type xterm) n'ont pas d'arbre, seulement L3 ;
  3. L2 Navigateur CDP — toutes les opérations sur les pages web (extension browser, Chromium headless dédié à l'agent) ;
  4. L3 Visuel/saisie de secours — capture d'écran grim (fiable), injection clavier (scripts/kb-inject.sh : wtype en mode utilisateur principal, fiable pour le texte et les combinaisons ; les touches de contrôle (Entrée/Tab) passent par ydotool avec sudo), injection pointeur (non fiable : dérive due à l'accélération, à utiliser seulement en dernier recours).

Face à une application qui « ne s'ouvre pas / ne fonctionne pas bien » : vérifiez d'abord si les prérequis L1 sont remplis (interrupteur a11y), puis utilisez L3 pour capturer l'état réel, ne refaites pas aveuglément.

1. Montage (une seule fois)

goose (~/.config/goose/config.yaml, format testé en version 1.54 ; le champ name: est obligatoire, son absence entraîne le rejet silencieux de l'extension) :

extensions:
  niri:
    type: stdio
    name: niri
    enabled: true
    cmd: /chemin/vers/AgentOS/scripts/env/with-niri-env.sh
    args: []
    env_keys: []
    envs: {}
    timeout: 300          # en secondes
  # desktop/system/files/session/a11y/browser/cred : structure identique,
  # cmd avec respectivement with-desktop-env.sh / with-system-env.sh / ... (huit lanceurs dans scripts/env/)

Autres frameworks (style JSON mcpServers pour Claude Code / Z Code, etc.) :

{
  "mcpServers": {
    "niri":    { "command": "/chemin/vers/AgentOS/scripts/env/with-niri-env.sh" },
    "desktop": { "command": "/chemin/vers/AgentOS/scripts/env/with-desktop-env.sh" },
    "system":  { "command": "/chemin/vers/AgentOS/scripts/env/with-system-env.sh" },
    "files":   { "command": "/chemin/vers/AgentOS/scripts/env/with-files-env.sh" },
    "session": { "command": "/chemin/vers/AgentOS/scripts/env/with-session-env.sh" },
    "a11y":    { "command": "/chemin/vers/AgentOS/scripts/env/with-atspi-env.sh" },
    "browser": { "command": "/chemin/vers/AgentOS/scripts/env/with-browser-env.sh" },
    "cred":    { "command": "/chemin/vers/AgentOS/scripts/env/with-cred-env.sh" }
  }
}

Points importants :

  • Utilisez le script de lancement, ne pointez pas directement vers node dist/index.js — le lanceur se charge de découvrir le socket IPC niri (chemin contenant le PID du compositeur, différent à chaque session, ex. /run/user/1000/niri.wayland-1.2762.sock) et de compléter l'environnement Wayland/dbus (XDG_RUNTIME_DIR/WAYLAND_DISPLAY/DBUS_SESSION_BUS_ADDRESS), afin que les outils soient disponibles même lorsqu'ils sont lancés depuis un environnement SSH/service ;
  • Test manuel du lanceur : timeout 2 scripts/env/with-niri-env.sh </dev/null, exit 0 signifie que tout est correct ;
  • Prérequis : Node ≥ 20, le dépôt a exécuté npm install && npm run build, et s'exécute sous l'utilisateur propriétaire de la session graphique niri.

2. Aide-mémoire des outils (groupés par extension, nom d'outil = <extension>__<outil>)

niri — Fenêtres/espaces de travail/lancement (L0)

OutilUtilisationParamètres clés
list_windowsLister toutes les fenêtres (id/app_id/titre/espace de travail/focus)—
list_workspacesLister les espaces de travail (l'index idx et l'id sont deux choses différentes, move utilise l'index ou le nom)—
list_outputsLister les écrans—
focus_windowMettre au premier plan avec focus (change la vue utilisateur, à utiliser avec précaution)id
focus_workspaceChanger d'espace de travail (change la vue utilisateur)reference: "3" ou nom
move_window_to_workspaceDéplacer une fenêtre (sans voler le focus, pour organiser)id? (défaut = fenêtre focus), reference
close_windowFermer une fenêtreid?
open_appLancer un programme sur le bureau de l'utilisateurcommand: tableau, ex. ["ghostty"]

a11y — Opérations dans les applications GUI (L1, AT-SPI2)

OutilUtilisationParamètres clés
a11y_list_appsLister les applications enregistrées sur le bus d'accessibilité—
a11y_dump_treeDécharger l'arbre d'accessibilité d'une application (trouver le nom du bouton/la structure)app
a11y_clickCliquer selon le nom accessible (sans focus, ne dérange pas l'utilisateur)app, buttonName
a11y_read_textsLire tout le texte non vide d'une application (écran/résultat/étiquette)app
a11y_set_textÉcrire dans un champ de texte par nom de nœudapp, match (sous-chaîne du nom, défaut * premier), text

Discipline testée : adressez-vous par nom, pas par index de l'arbre (la structure de l'arbre est reconstruite à chaque connexion AT) ; l'arbre GTK4 n'est complet qu'après enregistrement du client AT ; en cas de plusieurs instances d'un même nom, le pont résout la première enregistrée — lisez d'abord le texte pour discriminer l'état de l'instance, fermez les instances supplémentaires si nécessaire. Exception Chromium : l'arbre est construit paresseusement (le pont se déclenche automatiquement, un premier dump peut prendre 1 à 2 secondes de plus, c'est normal) ; pour écrire dans un champ de texte, utilisez la combinaison "grabFocus + kb-inject type" (les entrées de Chromium n'acceptent pas setTextContents) ; les clics sur les boutons de page ne fonctionnent pas (doAction est envoyé mais onclick ne s'exécute pas), les opérations sur les pages passent exclusivement par l'extension browser.

browser — Opérations web (L2, Chromium headless dédié à l'agent)

OutilUtilisationParamètres clés
browser_openNaviguer (le premier appel lance automatiquement le navigateur)url
browser_evalExécuter du JS dans la page, remplir des formulaires/cliquer/lire le contenu, tout passe par làCode JS
browser_screenshotCapture d'écran (navigateur headless, la partie visuelle repose entièrement sur cela)—

Action standard pour remplir un formulaire : après el.value = "...", exécuter obligatoirement el.dispatchEvent(new Event("input", {bubbles: true})), sinon les frameworks modernes ne reçoivent pas la saisie. En cas de CAPTCHA : arrêtez-vous et informez l'utilisateur, ne le contournez jamais automatiquement.

files — Bac à sable fichiers (L0, racine = ~/Agent/, tous les chemins en relatif)

OutilUtilisationParamètres clés
read_file / write_fileLire/écrire du texte (crée automatiquement les répertoires parents)path, content
list_dir / create_dirLister/créer un répertoirepath
move / deleteDéplacer/supprimer (va dans .trash, récupérable, n'utilisez pas rm shell)source/dest, path
find_by_nameTrouver un fichier par son nompattern
downloadTéléchargement http(s) dans le bac à sable (≤50 Mo / 60s, n'utilisez pas curl shell)url, path

desktop — Affichage/Notifications/Presse-papier/Confirmation (L0)

OutilUtilisationParamètres clés
openOuvrir un artefact : URL ou fichier ; pour les documents office, obligation de spécifier app: "libreoffice" (liste blanche, l'association MIME système n'est pas fiable)target, app?
notifyNotification bureau (trois niveaux voir §3)summary (obligatoire), body, urgency, action?
confirmDemander une décision à l'utilisateur (T1 : quatre bannières : autoriser/autoriser pour la session/refuser/refuser définitivement, 30s sans réponse = refus)summary (pas de contenu sensible), tier? (t1/t2, influence le texte)
clipboard_read / clipboard_writeLire/écrire le presse-papier—

session — Aquarium (session niri imbriquée dédiée à l'agent, tout le travail GUI s'y fait)

OutilUtilisation
agent_session_start / agent_session_stop / agent_session_statusCycle de vie de la session imbriquée (une fenêtre observable apparaît sur le bureau)
agent_open_appLancer une application dans l'aquarium (ex. gnome-calculator, chromium)
agent_list_windowsLister les fenêtres dans l'aquarium
agent_screenshotCapture d'écran ciblée de l'intérieur de l'aquarium (grim)

system — Requêtes système (L0 lecture seule, tout autorisé)

system_status / list_services / service_status / journal / network_info / list_packages / package_info / package_install (T2 confirmation forte : affiche une boîte de mot de passe polkit, nécessite une présence humaine ; en mode headless, timeout de 300s puis refus — ne pas appeler en mode non supervisé).

cred — Identifiants (l'agent obtient une référence, pas le texte clair)

cred_list (identifiants disponibles avec leur référence/nom de variable d'environnement) · cred_autofill (canal A : remplissage automatique de page, le texte clair est jeté immédiatement) · cred_exec (canal B : exécution déléguée via liste blanche + sortie masquée) · cred_inject (canal C : injection de variables d'environnement à courte durée de vie, révoquées en bloc à l'expiration). Toute opération nécessitant un mot de passe/token passe exclusivement par cred, il est interdit de demander le texte clair à l'utilisateur.

3. Conventions de comportement (discipline testée et efficace)

  1. Les artefacts sont stockés dans ~/Agent/, classés par downloads/ inbox/ reports/ notes/ canvas/ screenshots/ ; leur emplacement est automatiquement indexé dans les artefacts (http://127.0.0.1:7788/artifacts), si l'utilisateur demande « où est mon rapport précédent » → ouvrez cette page ou donnez le chemin relatif ;
  2. Priorité d'affichage : tableaux de bord/rapports/contenu interactif → écrivez un fichier HTML autonome dans canvas/<nom>/index.html puis open pour ouvrir http://127.0.0.1:7788/<nom>/ ; documents office → open avec app: "libreoffice" ; pages web → extension browser ;
  3. Trois niveaux de notification : achèvement → notify urgency=low + action ({kind:"open_path", path:"reports/x.fodt"} ou {kind:"open_url", url:...}, cliquer sur la notification mène directement à l'artefact) ; échec/nécessite attention rapide → urgency=critical + une phrase de conclusion + suggestion de cause ; pour une décision utilisateur → n'utilisez pas notify, passez par confirm (notify n'a pas de sémantique de choix). Tout résultat asynchrone doit être notifié, ne terminez pas en silence ;
  4. Confirmation et retenue : ne touchez pas à la fenêtre que l'utilisateur est en train d'utiliser, sauf demande explicite (d'abord list_windows pour identifier la cible) ; en cas de refus stratégique (isError avec mention « refus stratégique »), informez honnêtement, ne contournez pas ; les opérations GUI se font dans l'aquarium, ne volez pas le focus de l'utilisateur ;
  5. Les identifiants passent uniquement par la référence cred-mcp (discipline mentionnée après le tableau cred du §2).

4. Pièges d'environnement (tous déjà rencontrés)

PiègePhénomèneSolution
Le chemin du socket IPC niri change à chaque sessionniri msg ne se connecte pasUtilisez le lanceur (découverte automatique de NIRI_SOCKET), ne codez pas en dur
Le trousseau Chromium bloque les services réseauLe navigateur se lance et se bloqueLancez avec --password-store=basic (déjà intégré dans l'extension browser ; si vous lancez chromium vous-même, pensez à l'ajouter)
Verrouillage monoposte de sofficeSi LibreOffice est déjà ouvert, ouvrir un autre document du même type peut rester sans fenêtreVérifiez d'abord l'état du processus soffice ; pour ouvrir un document, utilisez app:"libreoffice" qui suit la sémantique du lanceur ; une sortie anormale précédente peut encore afficher une fenêtre "Document Recovery" (testé le 18 octobre 2026), en listant les fenêtres, ne la confondez pas avec la fenêtre du document cible
L'association MIME de LibreOffice n'est pas fiableFedora identifie fodt comme text/xml et l'ouvre avec un éditeuropen doit impérativement inclure app:"libreoffice"
Les applications Qt n'apparaissent pas sur le bus a11ya11y_list_apps ne les voit pasL'activation système est déjà globale (QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1 dans /etc/environment, persistant après redémarrage) ; si toujours invisible = application démarrée avant la mise en place de l'environnement ou non liée officiellement à Qt, redémarrez l'application
L'arbre a11y de Chromium/Electron est videLe dump ne produit rien① Lancez avec --force-renderer-accessibility (déjà par défaut dans l'extension browser) ; ② toolkit-accessibility doit être true avant le démarrage de l'application (déjà global ; une modification ultérieure est inefficace, il faut redémarrer l'application) ; ③ construction paresseuse de l'arbre, un premier dump déclenche le pont (voir discipline a11y §2)
Choix de l'injection clavierPour taper du texte ou des raccourcisscripts/kb-inject.sh : utilise wtype pour le texte et les combinaisons (utilisateur) ; les touches de contrôle (Entrée/Tab) ne fonctionnent pas avec wtype sur GTK, passez par ydotool (sudo) ; le chinois peut perdre le premier caractère, après la saisie vérifiez en lisant l'arbre a11y
L'aquarium a initialement la superposition des touches de raccourci niriLa capture d'écran est masquée par "Important Hotkeys"Injectez Esc pour fermer ; dans le bac à sable de l'agent, la connexion au socket ydotoold est impossible (root 600), utilisez niri__open_app pour exécuter l'injection dans l'environnement de bureau réel
Dérive du pointeur ydotoolLe positionnement absolu est imprécis (accélération libinput ≈0.5)Le pointeur n'est pas fiable ; l'injection clavier est fiable ; attention aux différences de chemin du socket /tmp/.ydotool_socket vs $XDG_RUNTIME_DIR
L'arbre GTK4 initial n'est pas completLe dump ne montre qu'une douzaine de nœudsFaites d'abord un a11y_list_apps/dump pour que le client AT s'enregistre, puis le deuxième dump sera complet (testé : 16→105 nœuds)
Confirmation T1/T2 en mode headless30s/300s sans réponse = refus automatiqueComportement attendu : les opérations d'écriture nécessitent la présence de l'utilisateur, ou en test, répondez par programme via org.agentos.Confirm1.Respond
Installation de paquet bloqué par le verrou packagekitddnf échoue parfoisAvant l'installation, systemctl stop packagekit (déjà géré par le helper T2)

5. Chemin de montée en puissance (quand l'application cible ne s'ouvre pas, essayez dans l'ordre)

L0 (couche système, toujours en premier) → L1 (a11y : GTK3/4/Qt déjà accessibles par défaut ; Chromium vérifiez le flag et l'ordre de toolkit-accessibility ; Electron tiers ajoutez le flag selon l'annexe B de capabilities.md) → L2 (pages web obligatoires) → L3 de secours (grim pour voir + kb-inject pour le clavier ; pointeur non fiable). Types encore inaccessibles : applications purement X11 (type xterm, sans arbre, L3 est le terminus), Java (nécessite JAB, voir annexe B de capabilities.md), UI du compositeur lui-même uniquement par injection de saisie — voir le tableau détaillé dans le dépôt sous docs/capabilities.md.

Skills associés