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, commecontinue). - 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(avecresume=tsi 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).