← Blog

Un agente de IA desplegado como código

El agente de IA de mi homelab no se configura a mano. Es un servicio más del repo, definido como código, con el mismo método que el resto: definición base reutilizable, override por nodo y secretos cifrados. Y se despliega en tres perfiles a partir de una sola definición.

Una definición, tres instancias

El stack base define el servicio una vez. Cada perfil lo hereda con extends y solo añade lo suyo (el nombre de perfil es un ejemplo):

hermes-<perfil>:
  extends:
    file: ../../../../stacks/applications/hermes-agent/compose.yaml
    service: hermes-agent

Tres perfiles aislados, una imagen y cero duplicación. Si cambia algo en el stack base, cambia en los tres.

La memoria es una ruta

La memoria de cada perfil es un directorio en el host. No lo crea el contenedor al arrancar: lo declara un archivo de tmpfiles con propietario fijo.

d /srv/homelab/hermes/<perfil>  0750  10000  10000  -

El usuario y grupo son el 10000. Y el montaje tiene una regla estricta:

volumes:
  - type: bind
    source: /srv/homelab/hermes/<perfil>
    target: /opt/data
    bind:
      create_host_path: false

Si la ruta no existe, el contenedor falla al arrancar en vez de crearla él mismo. No hay estados que se materializan por arte de magia: si no está preparado, no arranca.

Cero puertos al host

El agente no publica ningún puerto en el nodo. El tráfico entra por Traefik, con un label por perfil:

- traefik.http.routers.hermes-<perfil>.rule=Host(`hermes-<perfil>.example.com`)
- traefik.http.services.hermes-<perfil>.loadbalancer.server.port=9119

El puerto 9119 es el del dashboard, pero vive dentro de la red del proxy. El servidor de API escucha en el 8642 y ni siquiera se expone. Desde fuera no hay nada que tocar: solo los hostnames que el proxy conoce.

Secretos por nodo

Las credenciales viajan cifradas con SOPS y age, en el propio repo. Cada nodo tiene su regla de cifrado con dos destinatarios: el de administración y el del nodo. En el despliegue se descifran en /run/homelab/secrets con permisos restringidos. El texto plano solo existe donde debe existir.

Lo que aún falta

Este despliegue no está acabado, y no lo presento como tal. La imagen se fija por tag fechado (v2026.9.7), no por digest, así que la reproducibilidad no es al byte. El stack no define healthchecks ni límites de recursos. Y los secretos de los perfiles se cargan con required: false: si el materializador no ha corrido, el contenedor arranca igual, con lo que tenga. Son deudas conocidas, escritas en el registro operativo del homelab.

La regla

Un agente de IA no es un componente mágico: es un servicio con una imagen, una memoria y unos secretos. Tratarlo como código es lo que lo hace auditable, reproducible y capaz de fallar en voz alta en lugar de degradarse en silencio. La IA no cambia las reglas de la infraestructura: las cumple.