cc-sessions
Guía de recetas concretas de emacsclient --eval para gestionar sesiones de claude-code-ide.el desde
"Mayordomo" (o cualquier otra sesión con acceso al mismo servidor de Emacs). Los principios (por qué se
hace así) están en majordom.md; aquí solo las invocaciones listas para usar.
CRÍTICO: el único comando seguro para iniciar es claude-code-ide-start
claude-code-ide-continue, claude-code-ide-resume y el antiguo claude-code-ide (todos sin argumentos) —
NUNCA deben llamarse directamente en modo headless. Cada uno de ellos, cuando ya hay una sesión activa para el directorio, invoca
un (read-string "Instance name (empty for auto): ") bloqueante que se queda colgado para siempre sin un
usuario vivo frente al teclado (confirmado empíricamente en los tres). La única excepción es la
invocación interactiva directa M-x por parte de un humano.
claude-code-ide-start (firma (&optional instance-name continue resume)) cubre los tres
casos con una sola llamada que NUNCA pide el nombre de forma interactiva:
;; inicio normal de una nueva conversación
(let ((default-directory "/home/eugine/job/<proyecto>/")
(claude-code-ide-cli-extra-flags "--remote-control <proyecto>"))
(claude-code-ide-start "<nombre-o-nil>"))
;; en lugar de claude-code-ide-continue
(claude-code-ide-start "<nombre-o-nil>" t nil)
;; en lugar de claude-code-ide-resume (abre un selector interactivo DENTRO de la terminal de claude,
;; no a través del minibúfer de Emacs — la llamada en sí no bloquea emacsclient)
(claude-code-ide-start "<nombre-o-nil>" nil t)
instance-name (1.er argumento) nil ⇒ número automático (vedmid-2, vedmid-3...). Asígnale un valor explícito solamente
cuando el usuario haya nombrado él mismo el objetivo/nombre de la nueva copia — si no está claro, pregunta al usuario, no inventes.
Antes de iniciar: verifica el estado actual
(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\[<proyecto>" (buffer-name b))) (buffer-list)))
- No hay sesión activa →
(claude-code-ide-start nil t nil)(retomará la última conversación del proyecto, comocontinue). - Hay sesión activa → NUNCA la detengas "para reiniciarla". Levanta una COPIA ADICIONAL con el mismo
claude-code-ide-start(conresume=t, si el objetivo es elegir una conversación anterior concreta, o sin él — una nueva conversación al lado).
Después de iniciar: confirma remote-control buscando realmente en el búfer
La ausencia de congelamiento NO prueba que --remote-control haya funcionado (caso real: olvidó la bandera —
la sesión se levantó limpia, pero quedó sin remote).
(with-current-buffer "*claude-code[<proyecto>]*"
(save-excursion (goto-char (point-min))
(if (search-forward "remote-control" nil t) "ENCONTRADO" "NO ENCONTRADO")))
Si es NO ENCONTRADO — no siempre es un error: verifica el contenido completo del búfer (buffer-substring-no-properties (point-min) (point-max)), la línea puede estar fuera de lo renderizado, o (para sesiones grandes) fuera del
scrollback visible de eat — el propio terminal solo conserva la historia reciente, no toda la conversación.
Detener sesión: primero desactiva query-on-exit, luego stop
claude-code-ide-stop en sí mismo es seguro y NO depende de si la sesión tenía remote-control.
Pero la consulta normal de Emacs Buffer "..." has a running process; kill it? aparece DE FORMA ASÍNCRONA (en
process-sentinel, ya DESPUÉS de que claude-code-ide-stop ha retornado) — por lo tanto, un envoltorio let alrededor
de la propia llamada no sirve. Desactiva la bandera en el proceso DE ANTEMANO, con una llamada separada:
(let ((proc (get-buffer-process "*claude-code[<proyecto>]*")))
(when proc (set-process-query-on-exit-flag proc nil)))
(with-current-buffer "*claude-code[<proyecto>]*" (claude-code-ide-stop))
Si hay varias copias para el directorio (vedmid, vedmid:2, vedmid:masazh...) — invoca claude-code-ide-stop
en el contexto EXACTO de ese búfer (with-current-buffer), no a través de default-directory: el mensaje
confirmará cuál detuvo ("Stopping Claude Code vedmid:masazh...").
Si la consulta igualmente se escapó y se quedó colgada (ps aux | grep emacsclient muestra un proceso atascado) — NUNCA
intentes desbloquearla tú mismo (ni repetir --eval, ni enviar señales a emacs) — pide al usuario que responda
en el Emacs vivo. Consulta emacs.md para el contexto completo de este peligro.
Navegación en selectores interactivos (lista de reanudación, solicitudes de permisos)
La lista de sesiones (resume) y los menús de confirmación de permisos se renderizan DENTRO de la terminal (no a través
del minibúfer de Emacs) — se controlan con secuencias ANSI normales mediante process-send-string en bruto, no
con llamadas Elisp vía emacsclient --eval:
(process-send-string (get-buffer-process "*claude-code[<proyecto>]*") "\e[B") ; flecha abajo
(process-send-string (get-buffer-process "*claude-code[<proyecto>]*") "\e[A") ; flecha arriba
(process-send-string (get-buffer-process "*claude-code[<proyecto>]*") "\e[6~") ; Av Pág
(process-send-string (get-buffer-process "*claude-code[<proyecto>]*") "\r") ; Enter (confirmar)
Después de cada pulsación enviada, vuelve a leer el contenido del búfer (buffer-substring-no-properties), para
ver la nueva posición del cursor (❯) y el título (N of M), antes de seguir moviéndote o confirmar —
no te muevas al azar varios pasos sin verificar. Las teclas numéricas ("3") para seleccionar directamente un elemento
del menú de confirmación NO están confirmadas como funcionales — la navegación con flechas + Enter es más fiable.
Alternar modo de permisos (Shift+Tab) — algo distinto de auto-accept
La línea de estado del terminal (⏸ manual mode on, ⏵⏵ accept edits on, ⏸ plan mode on, ⏵⏵ auto mode on) se controla exclusivamente por el propio binario claude — Emacs no sabe nada de esto. Ciclo (Shift+Tab,
cuatro estados): manual → accept edits → plan → auto → manual.
(process-send-string (get-buffer-process "*claude-code[<proyecto>]*") "\e[Z")
El cambio A VECES genera una solicitud de confirmación intermedia de herramienta (Do you want to proceed?) — selecciona el elemento "Yes, and switch to auto mode" mediante navegación con flechas (no con número) +
Enter, si el objetivo es precisamente volver a auto.
claude-code-ide-toggle-auto-accept — función de Emaps aparte, no el mismo estado
No confundir con el ciclo de modo de permisos anterior. Esta función solo alterna una bandera Elisp en la estructura
de la sesión y afecta SOLO a la herramienta MCP openDiff (propuesta de vista ediff antes de guardar el
archivo): ON → ediff no se muestra, el archivo se guarda de inmediato (FILE_SAVED); OFF → ediff normal.
La línea de estado del terminal NO cambia con esta llamada.
(with-current-buffer "*claude-code[<proyecto>]*" (claude-code-ide-toggle-auto-accept))
Mostrar el contenido del búfer al usuario "como si él estuviera mirando"
(with-current-buffer "*claude-code[<proyecto>]*" (buffer-substring-no-properties (point-min) (point-max)))
Para sesiones grandes, recorta ((max (point-min) (- (point-max) N)) (point-max)) — el contenido completo puede ser
de megabytes, aunque el scrollback visible de eat siempre es limitado (la parte realmente renderizada no crece
indefinidamente).