v0.20.3

Hermes Agent v0.20.3


Overview

v0.20.3 — The Resilience Patch (el parche de la resiliencia). Lanzada el 16 de agosto de 2026. ~125 PR fusionados · ~250 commits · ~461 archivos modificados (+42,613 / −1,641) desde v0.20.2.

Un día después del Connections Patch, esta versión responde una pregunta más silenciosa: ¿qué pasa cuando tu automatización deja de funcionar sin hacer ruido y nadie te avisa? El programador de cron ahora sobrevive al agotamiento de descriptores de archivo, concilia los claims obsoletos contra el ledger de ejecuciones, rearma los trabajos periódicos atascados y recupera los disparos perdidos de los providers externos — mientras que last_fire_error hace visible cada fallo en la CLI, en el dashboard y en la salida de las propias herramientas del agente. Alrededor de este núcleo: la migración al SDK 2.x de MCP con soporte del protocolo sin estado de 2026-07-28, CommandCode como provider de primera clase, el /worktree y el seguro /rollback inspirados en Copilot CLI, el endurecimiento de la propiedad del runtime de Python en subprocesos y las correcciones de pérdida de datos en el handoff de sesiones.

Al ser una versión de parche, las notas oficiales son breves y la documentación curada completa llegará con v0.21.0. Esta página cubre las partes más valiosas de este ciclo.


Destacados

1. El programador de cron aprende a autocurarse

Tres modos de fallo por bloqueo silencioso que antes dejaban los trabajos muertos durante horas — mientras todo «parecía sano» — ahora se autocuran:

  • EMFILE (agotamiento de descriptores de archivo): tick() solía tragarse todos los OSError como si fueran «otra instancia tiene el bloqueo», así que un agotamiento de descriptores en el archivo de bloqueo se registraba como un tick exitoso y ningún trabajo volvía a ejecutarse. Ahora el errno de la adquisición del bloqueo se clasifica: solo la contención genuina se omite en silencio, los fallos reales se propagan como un tick fallido, y el ticker intenta recuperar descriptores con el mejor esfuerzo (gc.collect() + elevar el límite blando de nofile) con backoff exponencial limitado a 15 minutos (#88335, basado en #87796 de @webtecnica).
  • Claims en vuelo obsoletos: un claim filtrado más reciente que la ventana de edad (2×intervalo, 30 min) solía atascar un trabajo periódico hasta que un operador intervenía. El barrido ahora concilia contra el ledger de ejecuciones duradero: si la fila terminal de la ejecución demuestra que terminó, el claim se libera por la fuerza — con una salvaguarda para que un claim nuevo nunca se confunda con el resultado completado de la ejecución anterior (#88343, basado en #87259).
  • Estado de error persistido atascado: un trabajo periódico con last_status=error y next_run_at aparcado en el futuro era invisible para todos los barridos y sobrevivía a los reinicios del gateway. Ahora se rearma automáticamente en el siguiente tick — y el rearme respeta la legalidad de la programación, de modo que una expresión cron de solo días laborables nunca se dispara un sábado (#88339, basado en #87261).

2. Los disparos fallidos son visibles — y se recuperan

El incidente en producción del 2026-08-14 (4 fallos nocturnos consecutivos, sin evidencia más allá de una línea de log) produjo dos correcciones duraderas. Primero, cuando la ruta de disparo alojada no puede alcanzar el gateway, el trabajo recibe una marca last_fire_error que aparece en cronjob list, en hermes cron list (línea roja ⚠ Missed scheduled fire:) y en el dashboard; una ejecución exitosa la limpia, de modo que la marca siempre describe el estado de salud actual (#88555). Segundo, los providers de cron externos (Chronos / cron gestionado alojado) ahora cuentan con recuperación de disparos fallidos: cuando un disparo nunca llega y los reintentos se agotan, el gateway detecta el trabajo vencido y lo ejecuta localmente tras una ventana de gracia — cron.misfire_grace_minutes (por defecto 10; ≤0 lo desactiva). La interrupción cuesta minutos en lugar de un día perdido en silencio (#88563).

3. MCP: SDK 2.x + el protocolo sin estado de 2026-07-28

Hermes migró al SDK 2.x de MCP (#88180) y ahora habla el protocolo sin estado de 2026-07-28 de punta a punta (#88299). Los servidores sin handshake initialize se conectan sin configuración adicional a través de un único punto de estrangulamiento _negotiate_session() en los cuatro sitios de llamada de transporte (stdio, SSE, HTTP nuevo, HTTP heredado). La clave protocol por servidor: auto (predeterminado) intenta primero el handshake heredado y recurre a server/discover cuando el servidor lo rechaza — cero viajes de ida y vuelta extra para el parque existente; stateless sondea primero el descubrimiento; legacy desactiva el fallback. Las pistas SEP-2549 ttlMs/cacheScope de tools/list se capturan en la caché de esquemas con expiración por TTL, y el registro OAuth sigue la nueva especificación (application_type nativo, validación de iss según RFC 9207).

4. Nuevos providers: CommandCode (y Muse Spark en main)

CommandCode (commandcode.ai) es ahora un provider de primera clase — los perfiles commandcode (OpenAI chat completions) y commandcode-anthropic (Anthropic Messages, autenticación Bearer) detrás de una única COMMANDCODE_API_KEY, que cubren los planes GOAT/Pro/Max/Provider (~30+ modelos abiertos y cerrados, descubrimiento en vivo desde el endpoint público /provider/v1/models) (#88308, rescatando #32909). En main (posterior al tag), la Meta Model API (Muse Spark) se suma como plugin integrado: --provider meta-ai funciona listo para usar con MODEL_API_KEY (alias META_API_KEY/META_MODEL_API_KEY, anulación con META_BASE_URL) y un catálogo muse-spark-1.2 / muse-spark-1.2-contributor (#88565).

5. /worktree y el seguro /rollback — ediciones del agente que puedes deshacer

Dos comandos inspirados en Copilot CLI aterrizan en este ciclo. /worktree new [name] crea un worktree de git aislado a mitad de sesión (.worktrees/ dentro del repositorio, rama basada en la punta remota recién obtenida, worktree_sync respetado) y redirige las herramientas de terminal y archivos de la sesión hacia él — sin reiniciar; /worktree muestra el árbol activo y /worktree list los lista a todos, con la misma limpieza al salir de conservar lo no enviado que hermes -w. /rollback ahora usa por defecto la restauración segura: un ledger por proyecto de las escrituras del agente (sha256 de cada write_file/patch aplicado) le permite revertir solo lo que el agente cambió, eliminar los archivos creados por el agente y preservar tus ediciones manuales; --all/--force restaura todo, y los archivos omitidos se notifican con una pista.

6. Propiedad del runtime de Python en subprocesos

execute_code y compañía ahora son dueños de su entorno de subproceso Python: PYTHONHOME/PYTHONPATH se componen desde el runtime gestionado, sin heredar la contaminación del shell padre, lo que cierra una clase de sorpresas del tipo «en mi terminal funciona, en el agente se rompe» y refuerza la frontera para código no confiable.

7. Correcciones de pérdida de datos en el handoff de sesiones

Dos bugs de pérdida de datos reportados por usuarios quedan corregidos (#88244). Una condición de carrera CLI→gateway tras /handoff telegram podía finalizar la fila de sesión que el gateway estaba escribiendo activamente, haciendo desaparecer todo el tramo del handoff del historial y de session_search; la CLI ahora registra los ids de sesión transferidos y omite la finalización de limpieza. Por separado, un state.db corrupto que bloqueaba todos los mensajes ahora se muestra al usuario: el gateway difunde orientación de recuperación (incluidos hermes doctor --fix y sqlite3 .recover) a los canales principales en lugar de enterrar el fallo en los logs.

Mejoras

  • Escaneo de seguridad en instalación/actualización de plugins (inspirado en Claude-Cowork): las instalaciones se escanean en busca de contenido sospechoso antes de activarse.
  • Los archivos de texto UTF-16 se leen transcodificándolos a UTF-8 (port de MoonshotAI/kimi-code#2647); los IDs de tool-call de Gemini 3 se conservan entre reescrituras del adaptador (port de earendil-works/pi#7494).
  • Autocuración de worktrees git: un hermes -w fallido o con timeout limpia lo que dejó a medias (directorio parcial, entrada administrativa LOCKED, rama huérfana), y la pasada de mantenimiento al arrancar vuelve a empaquetar cuando los packs se dispersan — los 39 packs (638 MB) del incidente de agosto quedaron en 2 (287 MB) y la creación de worktrees pasó de un timeout de 30 s a 0,5 s (#88306).
  • Contratos de runtime de Cua Driver 0.20: computer use verifica y autorrepara un driver instalado que incumple el contrato de runtime al actualizar y en ejecución (familia #87646).
  • Escritorio: el renderizado de DiffusionCanvas está acotado (política de pausa, presupuesto de 15 fps, tope de instancias), la animación inactiva del pixel-egg duerme, los chats grupales de Bot Mode renderizan Markdown y los escritorios de gateways remotos ya no muestran un escritorio local fantasma por defecto (#88564, #88406, #88553, #88554).
  • Delegación: el trabajo sin commitear de un subagente se conserva cuando falla la inspección git, y los agentes padres reciben aviso cuando un worktree se conservó sin inspeccionar.

Correcciones

  • Carrera CLI→gateway en /handoff que perdía el tramo del handoff (#88234); la corrupción de state.db ahora se muestra con orientación de recuperación (#88235).
  • Matrix: nombres de archivo de medios desnudos vacíos provenientes de los cuerpos m.audio/m.file/m.video; Telegram prefiere las IPs IPv4 de la API y registra el stick de primera elección como info.
  • Cron: run_claim se limpia en los trabajos de una sola ejecución cuando falla el despacho; la remediación de la deriva se dirige a los pins propiedad del usuario.
  • Compresión: una rotación abortada ya no agranda el padre que no pudo publicar.
  • Escritorio: la espera de asentamiento previa al arranque ya no puede dejar el composer cerrado; un brazo de restauración/edición mantiene el composer utilizable.

Actualización

hermes update

Después de actualizar, ejecuta hermes doctor para verificar la instalación y reinicia el gateway (hermes gateway) para que los cambios de plataforma surtan efecto. Si usas un provider de cron externo, revisa hermes cron list una vez para confirmar que last_fire_error no muestra nada pendiente.

← Hermes Agent Changelog