Cuando tus dedos pulsan Esc: keybindings de Vim para el composer del CLI de Hermes (y el nombre de la rama en tu barra de estado)

Has escrito un prompt largo en Hermes y justo antes de pulsar Enter te das cuenta de una palabra mal escrita en medio. Tus dedos pulsan Esc y luego dd, y el composer no hace absolutamente nada. Con los keybindings emacs por defecto, Esc no es “salir del modo insert”: es una tecla de cancelar/limpiar, y dd simplemente se convierte en dos caracteres de texto. Si llevas una década en vim, ese medio segundo de fricción es difícil de explicar a quien no lo ha vivido.
Ahora hay una respuesta oficial. El composer clásico del CLI puede usar keybindings de vi/vim, y la configuración es más pequeña de lo que esperarías: una clave de config y ningún slash command nuevo.
Activarlo: display.vim_mode
Añade una línea bajo la sección display de ~/.hermes/config.yaml:
display:
# Solo CLI: keybindings vi/vim en el composer de entrada (Esc → NORMAL, i → INSERT)
# El modo NORMAL / INSERT / REPLACE en vivo se muestra a la derecha de la barra de estado.
# Solo config, se lee al arrancar.
vim_mode: true
Luego abre tu config con hermes config edit (o tu propio editor), guarda y reinicia Hermes.
Una trampa que conviene quitar del medio cuanto antes: no existe ningún slash command /vim. Una iteración temprana de esta función incluía uno con subcomandos on|off|status, pero se retiró antes del merge, y por una razón sensata. Sus vecinos (/statusbar, /battery, /timestamps) alternan elementos de visualización en el momento, mientras que los keybindings son un hábito de edición, y atarlos a la configuración es más coherente que cambiarlos sesión a sesión. Así que si ves /vim on escrito por ahí, ese es el estado intermedio descartado: escribir eso no hace absolutamente nada.
Cómo se siente en la práctica
El comportamiento encaja con lo que esperan tus dedos:
- Esc entra en modo NORMAL, donde las teclas son comandos y no texto;
i(oa,oy compañía) vuelve a modo INSERT para escribir normal;- la barra de estado muestra el modo actual en su borde derecho, uno de
NORMAL,INSERToREPLACE. Esto es genuinamente útil, no decoración: en un prompt multilínea, olvidar en qué modo estás es el fastidio clásico, y una etiqueta persistente elimina la mayoría de los momentos de “por qué no pasa nada cuando escribo”.
Esa etiqueta es en vivo: sigue tus pulsaciones de Esc e i en lugar de fijarse al arrancar. Por debajo, la barra de estado la construye dinámicamente a partir del modo de edición actual (_vim_mode_label en cli_status_bar_mixin.py).
¿Y si nunca has usado vim? El valor por defecto es off, lo que mantiene los keybindings emacs estándar de prompt_toolkit: no cambies nada, no notas nada. Esa postura opt-in es justo por lo que esto llegó como un interruptor de configuración.
Un compañero que merece la pena: tu rama git actual en la barra de estado
Ya que estamos con la barra de estado, hay un segundo campo “apagado por defecto, actívalo a propósito”: la rama git actual.
En una máquina con varios repositorios y worktrees, “¿en qué rama está de verdad esta sesión?” es una pregunta frecuente y con consecuencias, sobre todo después de que un agente te haya editado archivos y quieras estar seguro de qué rama se llevó el golpe. Fíjala en la barra de estado y la tendrás siempre a un vistazo:
display:
status_bar:
# No vacío = solo se muestran estos campos (se mantiene el orden interno; la
# config controla la visibilidad, no el orden). Una lista vacía = el conjunto por defecto.
fields: ["model", "git_branch", "duration"]
Los campos disponibles incluyen model, context_pct, cache_hit, latency, tps, compressions, bg_tasks, bg_subagents, goal, git_branch (se dibuja como ⎇ branch), duration, focus, yolo, battery, title y total_tokens. Dos reglas importan:
- Una lista no vacía es una whitelist: solo se muestran los campos que nombres; una lista vacía restaura el conjunto por defecto. El orden sigue siendo interno: la configuración solo decide la visibilidad.
- Los terminales estrechos descartan campos automáticamente. Cuando la ventana se queda corta, los campos anchos como
context_detail,prompt_elapsedeidle_sincese eliminan en lugar de apretarse. Es el comportamiento previsto, no una config rota.
Si lo que quieres es simplemente alternar la barra de estado, /statusbar se encarga; la lista de campos es configuración.
Advertencias
- Reinicia después de editar.
vim_modese lee al arrancar, así que una edición de config en caliente no cambiará el modo en una sesión que ya está corriendo. - Solo toca el composer. El cambio afecta a la caja de entrada donde escribes prompts, no a todas las demás superficies de interacción y, desde luego, no a cómo trabaja el agente.
- Es específico del CLI. Los keybindings pertenecen al composer clásico del CLI; la app de escritorio y otras superficies TUI tienen su propia lógica de entrada. No esperes que un solo interruptor las cambie todas.
- No es todo vim. Este es el modo de edición vi de prompt_toolkit: movimiento, borrado, entrada en modo insert; edición cotidiana, no una sesión de Neovim con plugins y registros elaborados.
- La función tiene precedente. La petición original es el issue #4254, y casi al mismo tiempo GitHub Copilot CLI llevó el modo vim a disponibilidad general (sus notas de la v1.0.84-2 nombran tanto un comando
/vimcomo un ajusteeditorMode). Los dos proyectos coinciden en el fondo: los hábitos de edición en terminal merecen respeto.
Si estás ajustando tu setup de CLI, tres artículos relacionados de aquí merecen una lectura: la guía de la command palette con Ctrl+P, el análisis a fondo de las métricas de la barra de estado y quitar el techo de max-turns para sesiones largas. Montar una máquina desde cero empieza en la guía de instalación.
La versión corta
En una frase: ¿quieres teclas de vim? Escribe display.vim_mode: true y reinicia, y no busques un comando /vim porque no existe.
Tres cosas que llevarte:
- Apagado por defecto, así que nada cambia a menos que lo pidas; una vez activado, la barra de estado muestra NORMAL / INSERT / REPLACE de forma permanente.
- Plantéate añadir
git_branchadisplay.status_bar.fields: en un entorno con varias ramas evita toda una clase de errores tontos. - Este cambio se fusionó después del tag v0.21.2, así que ahora mismo vive en
mainen lugar de en una versión etiquetada;hermes updatetraemain, o espera al siguiente release.
Para quien arrastra memoria muscular de vim en el terminal, es un cambio pequeño que usarás varias veces al día.