EugineKosenko/majordom

Gestion des sessions claude-code-ide.el dans un Emacs live via emacsclient headless — démarrer/continuer/reprendre sans requêtes bloquantes, arrêt sécurisé, basculement du mode de permission et de l'auto-accept, navigation dans les sélecteurs interactifs.

Qu'est-ce que majordom ?

Ce skill permet à un agent AI (le « Majordome ») de contrôler à distance les sessions `claude-code-ide.el` dans un serveur Emacs, sans intervention humaine. Il fournit des recettes précises en Emacs Lisp via `emacsclient --eval` pour démarrer, continuer, reprendre ou arrêter des sessions Claude Code sans bloquer. Il couvre également la navigation dans les listes interactives (resume, permissions) par envoi de séquences ANSI, ainsi que le basculement entre les modes de permission (manuel, accepter les modifications, plan, auto) et l'activation/désactivation de l'auto-accept pour l'outil MCP `openDiff`. Le skill est conçu pour être utilisé avec Claude Code, Cursor, Codex ou tout autre agent ayant un client Emacs. Il repose sur des appels headless à `emacsclient` et évite les commandes interactives qui pourraient bloquer indéfiniment.

Compatible avec✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/EugineKosenko/majordom/tree/HEAD/skills/cc-sessions

Installed? Explore more Développement et programmation skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Demander à votre IA préférée

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

Documentation

cc-sessions

Guide de recettes concrètes emacsclient --eval pour gérer les sessions claude-code-ide.el depuis le « Majordome » (ou toute autre session ayant accès au même serveur Emacs). Les principes (pourquoi ainsi) se trouvent dans majordom.md ; ici seuls les appels prêts à l'emploi.

CRITIQUE : la seule commande de démarrage sûre est claude-code-ide-start

claude-code-ide-continue, claude-code-ide-resume et l'ancien claude-code-ide (tous sans arguments) — ne jamais les appeler directement en headless. Chacune, lorsqu'une session active existe déjà pour le répertoire, déclenche un (read-string "Instance name (empty for auto): ") bloquant qui se bloque indéfiniment sans utilisateur humain au clavier (confirmé empiriquement sur les trois). La seule exception est l'appel interactif M-x par un humain directement.

claude-code-ide-start (signature (&optional instance-name continue resume)) couvre les trois cas en un seul appel, qui ne demande jamais le nom de manière interactive :

;; démarrage normal d'une nouvelle conversation
(let ((default-directory "/home/eugine/job/<projet>/")
      (claude-code-ide-cli-extra-flags "--remote-control <projet>"))
  (claude-code-ide-start "<nom-ou-nil>"))

;; équivalent de claude-code-ide-continue
(claude-code-ide-start "<nom-ou-nil>" t nil)

;; équivalent de claude-code-ide-resume (ouvre le sélecteur interactif À L'INTÉRIEUR du terminal claude,
;; pas via le minibuffer Emacs — l'appel lui-même ne bloque pas emacsclient)
(claude-code-ide-start "<nom-ou-nil>" nil t)

instance-name (1er argument) nil ⇒ numéro automatique (vedmid-2, vedmid-3...). Ne le définir explicitement que lorsque l'utilisateur a lui-même nommé la cible/nom de la nouvelle copie — si incertain, demander à l'utilisateur, ne pas inventer soi-même.

Avant de démarrer : vérifier l'état existant

(mapcar (lambda (b) (list (buffer-name b) (and (get-buffer-process b) (process-status (get-buffer-process b)))))
        (seq-filter (lambda (b) (string-match-p "claude-code\\[<projet>" (buffer-name b))) (buffer-list)))
  • Aucune session active → (claude-code-ide-start nil t nil) (reprendre la dernière conversation du projet, comme continue).
  • Session active présente → NE JAMAIS l'arrêter « pour redémarrer ». Lancer une copie SUPPLÉMENTAIRE avec le même claude-code-ide-start (avec resume=t si l'objectif est de choisir une ancienne conversation spécifique, ou sans pour une nouvelle conversation à côté).

Après le démarrage : confirmer le remote-control par une recherche réelle dans le buffer

L'absence de blocage ne prouve PAS que --remote-control a agi (épisode : oubli du flag — session lancée proprement, mais restée non-remote).

(with-current-buffer "*claude-code[<projet>]*"
  (save-excursion (goto-char (point-min))
    (if (search-forward "remote-control" nil t) "FOUND" "NOT FOUND")))

Si NOT FOUND — pas toujours une erreur : vérifier le contenu complet du buffer (buffer-substring-no-properties (point-min) (point-max)), la ligne peut être hors de ce qui est rendu, ou (pour les grandes sessions) hors du scrollback visible d'eat — le terminal lui-même ne conserve que l'historique récent, pas toute la conversation.

Arrêt d'une session : d'abord désactiver query-on-exit, puis stop

claude-code-ide-stop est sûr en soi et NE dépend PAS du fait que la session avait remote-control. Mais la demande Emacs habituelle Buffer "..." has a running process; kill it? apparaît de façon ASYNCHRONE (dans process-sentinel, APRÈS que claude-code-ide-stop est revenu) — donc une enveloppe let autour de l'appel lui-même ne suffit pas. Désactiver le flag sur le processus AU PRÉALABLE, par un appel séparé :

(let ((proc (get-buffer-process "*claude-code[<projet>]*")))
  (when proc (set-process-query-on-exit-flag proc nil)))
(with-current-buffer "*claude-code[<projet>]*" (claude-code-ide-stop))

Si pour le répertoire il y a plusieurs copies (vedmid, vedmid:2, vedmid:masazh...) — appeler claude-code-ide-stop dans le contexte DU buffer concerné (with-current-buffer), pas via default-directory : le message confirmera laquelle a été arrêtée ("Stopping Claude Code vedmid:masazh...").

Si la demande a tout de même sauté et s'est bloquée (ps aux | grep emacsclient montre un processus coincé) — NE JAMAIS tenter de débloquer soi-même (aucun --eval répété, aucun signal vers emacs) — demander à l'utilisateur de répondre dans l'Emacs live. Voir emacs.md pour le contexte complet de ce danger.

Navigation dans les sélecteurs interactifs (liste resume, demandes de permission)

La liste des sessions (resume) et les menus de confirmation des autorisations sont rendus À L'INTÉRIEUR du terminal (pas via le minibuffer Emacs) — ils sont contrôlés par des séquences ANSI normales via process-send-string brut, pas par des appels emacsclient --eval Elisp :

(process-send-string (get-buffer-process "*claude-code[<projet>]*") "\e[B")   ; flèche bas
(process-send-string (get-buffer-process "*claude-code[<projet>]*") "\e[A")   ; flèche haut
(process-send-string (get-buffer-process "*claude-code[<projet>]*") "\e[6~")  ; Page Down
(process-send-string (get-buffer-process "*claude-code[<projet>]*") "\r")     ; Entrée (confirmer)

Après chaque pression envoyée, relire le contenu du buffer (buffer-substring-no-properties) pour voir la nouvelle position du curseur (❯) et l'en-tête (N of M), avant de se déplacer ou de confirmer — ne pas se déplacer à l'aveugle de plusieurs pas sans vérifier. Les touches numériques ("3") pour la sélection directe d'un élément du menu de confirmation ne sont pas confirmées comme fonctionnelles — la navigation par flèches + Entrée est plus fiable.

Basculement du mode de permission (Shift+Tab) — chose distincte, pas auto-accept

La barre d'état du terminal (⏸ manual mode on, ⏵⏵ accept edits on, ⏸ plan mode on, ⏵⏵ auto mode on) est gérée exclusivement par le binaire claude lui-même — Emacs n'en sait rien. Cycle (Shift+Tab, quatre états) : manual → accept edits → plan → auto → manual.

(process-send-string (get-buffer-process "*claude-code[<projet>]*") "\e[Z")

Le basculement déclenche PARFOIS une demande de confirmation d'outil intermédiaire (Do you want to proceed?) — choisir l'élément "Yes, and switch to auto mode" via navigation par flèches (pas par chiffre) + Entrée, si l'objectif est précisément de revenir en mode auto.

claude-code-ide-toggle-auto-accept — fonction Emacs distincte, pas le même état

Ne pas confondre avec le cycle de mode de permission ci-dessus. Cette fonction bascule uniquement un flag Elisp sur la structure de session et N'AFFECTE QUE l'outil MCP openDiff (proposition de revue ediff avant enregistrement du fichier) : ON → ediff ne s'affiche pas, le fichier est enregistré directement (FILE_SAVED) ; OFF → ediff normal. La barre d'état du terminal n'est PAS modifiée par cet appel.

(with-current-buffer "*claude-code[<projet>]*" (claude-code-ide-toggle-auto-accept))

Afficher le contenu du buffer à l'utilisateur « comme s'il regardait »

(with-current-buffer "*claude-code[<projet>]*" (buffer-substring-no-properties (point-min) (point-max)))

Pour les grandes sessions, tronquer ((max (point-min) (- (point-max) N)) (point-max)) — le contenu complet peut faire des mégaoctets, bien que le scrollback visible d'eat soit toujours limité (la partie réellement rendue ne croît pas indéfiniment).

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

EugineKosenko/majordom

Analyse a Figma .fig file kept in a project's spcfctn/ui/draft. Unpacks and decodes it offline (kiwi), breaks it into sections, screens, text rows and rasters, writes the analysis to spcfctn/ui/*.md, then fetches the author's comments through the figma MCP by link, binds them to screens by geometry, checks that the comments agree with the content of the file and asks the user to clarify what does not. Use when the user asks to analyse, decode or re-read a .fig file or Figma wireframes, or to refresh spcfctn/ui after a new export.

EugineKosenko/majordom

Scaffold a new component/command/crate in this user's literate org-babel Rust style (modeled on ads-back's crates/api and crates/cli patterns — one org file per command with a :tangle skeleton block, Декларації-before-Визначення/Дії noweb blocks, one heading per concern). Use whenever the user asks to add a new component, command, procedure, CLI subcommand, Yew component, module, or crate in an org-babel-literate Rust project (ads-back, ads-front, or similar), including wiring a brand-new crate's config.org/env.org/main.org into the workspace's federated config.org.

EugineKosenko/majordom

Bootstrap a new project in this user's standard layout — .claude-root, .dir-locals.el (root: org-link abbreviation), code/, spcfctn/code/ (with its own git repository) and a .claude/ directory with its own git repository and a CLAUDE.md that fixes the project's prose language and its short two-letter project code (chosen by the user from options the agent proposes) — and translate any files already present into that language. Use whenever the user asks to create, start, set up, initialise or "оформити" a new project (or to bring an existing bare directory to the standard layout).

EugineKosenko/majordom

Check org/md prose in this user's projects against the prose-formatting conventions in ~/.claude/rules/org-babel.md (~...~ vs =...= markup, acronym casing, /.../ glossary terms, real org-links vs italics/plain text, spaces around / between two markups, trailing newline, fill-column). Use proactively right after editing prose paragraphs in an .org or .md file (in place of manually re-deriving each rule from memory), and whenever the user explicitly asks to check/lint org rules or compares the request to running clippy.

Skills associés