Saltar al contenido principal

Hermes Agent: 7 dolares por nada

· 9 min de lectura
Oscar Adrian Ortiz Bustos
Ingeniero en Gestión y Desarrollo de Software
Contando lecturas...

Introducción

Instalé Hermes Agent en mi servidor para vigilar dependencias desactualizadas en mis PRs de GitHub sin tener que estar pendiente: usuario dedicado sin sudo, systemd hardened, toolset recortado a 9 herramientas de solo lectura, cron cada 5 minutos en vez de webhook público. Lo que no hardening fue cuánto me iba a costar correrlo sin supervisión.

Cuatro días después, el dashboard de DeepSeek mostraba el balance en -$0.01 — de $20 cargados no quedaba nada — y el agente no había reportado ni una sola dependencia. Esto es la reconstrucción de qué pasó, con los números reales.

WelcomeBanner

Cómo debía funcionar

Flujo esperado del vigía de dependencias

1

Cron dispara cada 5 minutos

Trigger programado, sin webhook público.

2

Lista PRs abiertos

mcp__github__list_pull_requests

3

Lee manifiestos de cada PR

package.json, requirements.txt, go.mod, etc. vía get_file_contents

4

Compara versiones

Contra el registro correspondiente (npm, PyPI, crates.io)

5

¿Hay dependencias desactualizadas?

Si no, termina en silencio ([SILENT])

6

Genera reporte interno

Nota local o notificación, sin comentar en el PR

El síntoma: créditos en cero sin haber visto un solo resultado

No lo noté por una alerta ni por un log — lo noté porque entré al panel de DeepSeek por otra razón y vi esto:

Dashboard de DeepSeek mostrando el balance en -$0.01, costo total de $7.25 filtrado por la API key Hermes-Bot, 10,697 requests y 138,737,672 tokens

El gráfico de gasto por día mostraba algo bien claro: cero actividad durante semanas, y de golpe un pico vertical los últimos 4-5 días que se comió todo el saldo. La columna "API Key" del dashboard señalaba directo a Hermes-Bot.

Mi primera reacción fue de sospecha de compromiso — el mismo instinto que tuve con lo de Gitea: algo externo abusando de una credencial mía. Pero acá no había nada expuesto a internet, el token estaba scopeado, y el agente corría en un usuario sin privilegios. Tenía que ser otra cosa.

La investigación: cuando la propia herramienta te miente

Lo primero que corrí fue lo obvio:

hermes cron runs github-dependency-watch
No cron execution attempts recorded.

Según esto, el job nunca había corrido. Eso no cuadraba con nada — el gasto era real, la API key era real, y el gráfico de DeepSeek mostraba tráfico sostenido durante días. hermes cron status sí confirmaba que el scheduler estaba vivo (Ticker heartbeat: 18s ago, Next run avanzando cada 5 minutos), así que el comando de historial estaba simplemente roto o no trackeaba lo que yo esperaba. Tuve que ir a otra fuente.

hermes insights

Ahí apareció la foto completa:

Overview

MétricaValor
Sessions817
Messages22,474
Tool calls13,525
User messages817
Input tokens11,096,194
Output tokens4,121,282
Total tokens138,731,076

Platforms

PlatformSessionsMessagesTokens
cron81622,472136,477,098
cli126,126

816 sesiones cron en poco más de 4 días. La sesión más pesada llegó a 52 tool calls y 61,683 tokens en una sola corrida. Y el desglose de herramientas usadas fue lo que terminó de explicar todo:

Top Tools

ToolCalls%
terminal4,37027.3%
tool_describe3,54222.1%
tool_call2,52715.8%
mcp__github__list_pull_requests1,2798.0%
tool_search1,0816.8%
read_file1,0176.4%
search_files9095.7%
mcp__github__get_me7474.7%

terminal + tool_describe + tool_call + tool_search suman 71.9% de todas las llamadas. Eso no es "leer PR, detectar dependencia vieja" — es el agente abriendo un entorno de terminal, describiendo y buscando herramientas disponibles, en cada una de las 816 corridas, antes de siquiera tocar GitHub. El trabajo real (mcp__github__list_pull_requests, pull_request_read, get_file_contents) es una fracción chica del total.

Adónde fue el gasto realmente

Cron (5m)

Hermes Agent

terminal / describe / search

72% del gasto, 0% trabajo real

GitHub MCP

28% del gasto, trabajo real

DeepSeek API

$7.25 cobrados en total

El detalle que más me dolió

Revisando los logs de la primera corrida (guardados de cuando armé el job), ya se veía la pista: agent returned [SILENT] — skipping delivery. El agente corría, gastaba tokens abriendo terminal y describiendo tools, y terminaba sin encontrar ninguna dependencia que reportar. Se repitió así, en automático, cada 5 minutos, durante 4 días.

La confirmación: el dashboard real vs. la estimación de Hermes

hermes insights trae su propia estimación de costo: ~$3.05, con una advertencia de "60 sessions (no pricing data)". El dashboard real de DeepSeek marcó $7.25 en el mismo período — más del doble de lo que la herramienta local calculaba. La diferencia probablemente viene de que DeepSeek metió un esquema de precios peak/off-peak a mediados de agosto, y el estimador local de Hermes no lo tiene actualizado. Si hubiera confiado solo en el número que me mostraba hermes insights, habría subestimado el problema por completo.

Estimación local vs. dashboard real

hermes insights (estimado)

  • ~$3.05
  • 60 sessions sin pricing data
  • Basado en tarifas desactualizadas

Dashboard DeepSeek (real)

  • $7.25
  • Fuente de verdad del proveedor
  • Incluye esquema peak/off-peak de agosto

Timeline del incidente

Del alta del cron a la contención

21 ago, ~15:40

Creo github-dependency-watch: every 5m, --continuity, sin límite ni tope de gasto

21 ago, 15:52

Primera corrida: [SILENT] — skipping delivery, ya usó terminal varias veces

21–24 ago

El job dispara cada 5 min sin supervisión, sesión tras sesión

25 ago, noche

Reviso el dashboard por otra razón: balance en -$0.01, cero dependencias reportadas

25 ago (detección)

hermes cron runs dice 'sin ejecuciones' (falso); hermes insights revela 817 sesiones, 138.7M tokens, 71.9% overhead

25 ago (contención)

hermes cron pause github-dependency-watch: job pausado

La contención: parar el sangrado primero, investigar después

hermes cron pause github-dependency-watch

No hubo mucho más que decidir en este paso — el error no era de seguridad (nadie más tenía la API key, nada estaba comprometido), era de diseño de automatización: un intervalo demasiado agresivo, sin tope de costo, y un toolset más amplio del que la tarea necesitaba.

El hardening: lo que voy a cambiar antes de reactivarlo

Todavía estoy validando la forma correcta de aplicar algunos de estos puntos en Hermes — lo dejo anotado tal cual, sin inventar sintaxis que no confirmé:

  1. Intervalo mucho más largo. 5 minutos no tiene sentido para "revisar si hay dependencias nuevas en PRs abiertos" — cada 30-60 minutos alcanza sobrado para este caso de uso, y corta el volumen de sesiones a una fracción.
  2. Sacar terminal del alcance de este job. El flujo de "leer PR y detectar dependencia vieja" no debería necesitar terminal para nada — solo el MCP de GitHub. Voy a revisar si Hermes permite acotar el toolset por cron job (hermes profile, o algo equivalente) en vez de heredar todo lo habilitado globalmente.
  3. Tope de gasto real, no solo estimación local. Configurar el límite de balance/alertas directo en el dashboard de DeepSeek (ya lo tenía como "disabled" — irónico) en vez de confiar en que hermes insights me avise a tiempo.
  4. Reusar la infraestructura de ntfy que ya tengo (armada después del incidente de Gitea) para un watcher de costo: si el gasto diario de una API key supera un umbral, que me llegue una notificación al celular en vez de enterarme por casualidad cuatro días después.
  5. Revisar --continuity de cerca. La idea era que cada corrida supiera qué dependencias ya se habían reportado y no repitiera trabajo — pero si cada corrida sigue gastando tool calls en describir/buscar herramientas desde cero, --continuity no está evitando el overhead real, solo el contenido del reporte.
Lecciones aprendidas
  • Un cron sin tope de costo es un cheque en blanco, sin importar cuánto hayas hardened el usuario del sistema. El aislamiento de proceso no te protege de un loop que gasta plata legítimamente, con tus propias credenciales, haciendo exactamente lo que le pediste (aunque de forma ineficiente).
  • Las herramientas de observabilidad de la propia plataforma pueden mentir o subestimar. hermes cron runs decía "cero ejecuciones" con 816 corridas reales. hermes insights estimaba $3.05 contra $7.25 reales. Cuando algo no cuadra, la fuente de verdad es el proveedor final (el dashboard de DeepSeek), no la capa intermedia.
  • "Silencioso" no es gratis. Un agente que corre, no encuentra nada que hacer, y termina sin avisar ([SILENT]) igual gastó tokens llegando a esa conclusión — 816 veces.
  • El intervalo de un cron es una decisión de costo, no solo de latencia. Elegí 5 minutos pensando en "que detecte rápido", sin calcular cuántas corridas eso significa en un mes ni cuánto cuesta cada una, aunque sea barata individualmente.

Conclusión

Nadie entró a nada esta vez, pero el resultado fue el mismo que con el minero en Gitea: algo corrió sin que yo lo estuviera mirando, y me enteré tarde. Ahí faltaba un candado en la puerta; acá faltaba un límite de gasto en el cron.

La próxima vez, el tope de gasto y la alerta van en el setup inicial, no después de vaciar el balance. Barato no es lo mismo que gratis.

"Trust, but verify."

Ronald Reagan
Escrito por un humano