Kernl

0.4.0 · · Release en GitHub

Kernl 0.4.0: proyectos con aprobación, voz y agentes que retoman

El mundo 3D de Kernl con las oficinas en lotes fijos, carteles de lote disponible y un edificio Warehouse aportado por una extensión

Kernl 0.4.0 es la versión más grande hasta ahora. El cambio de fondo: una oficina deja de ser una sola cosa y pasa a trabajar por proyecto, y nada de lo que escriben los agentes sale sin que lo apruebes.

Proyectos: nada sale sin tu aprobación

Hasta ahora una oficina era una oficina. Ahora puede atender varios productos o negocios, y los runs, la memoria, los aprendizajes, las cartas y los schedules pertenecen a un proyecto.

El cambio que de verdad importa es otro. En un run de proyecto, las herramientas que publican o envían algo escriben un borrador a un outbox en lugar de mandarlo. Nada sale hasta que lo aprobás. Recién ahí va por email, newsletter, WhatsApp o LinkedIn, respetando los flags de no-contactar y los links de baja. Las aprobaciones pendientes aparecen en la vista de Trabajo.

Es la diferencia entre un agente que te redacta algo y un agente que le escribe a tus clientes mientras no mirás.

Hablarle al Chief

Hay un botón de micrófono en el chat y en el canal del Chief, con respuestas habladas opcionales y notas de voz en Telegram.

Lo interesante es que los motores por defecto son locales y gratis: whisper.cpp para escuchar y Piper para hablar. Si preferís la nube, el reconocimiento puede ir por Groq u OpenAI y la voz por OpenAI o ElevenLabs. La voz española de Piper pesa unos 110 MB y se baja sola la primera vez.

El correo y WhatsApp, desde la interfaz

Conectás un buzón desde Settings o desde el asistente inicial: detecta el proveedor por la dirección, prueba IMAP y SMTP antes de guardar, y te guía con las contraseñas de aplicación cuando hacen falta. Los mensajes se ven en la vista de mail, con los HTML renderizados y las imágenes remotas bloqueadas, y las cuentas de Gmail separadas en Principal, Novedades, Promociones, Social y Foros.

WhatsApp se vincula con QR o código telefónico, y la sesión sobrevive a las actualizaciones, así que no te vuelve a pedir el QR en cada update.

Runs que retoman donde quedaron

Un run cortado por un reinicio sigue desde donde estaba. Las llamadas a herramientas cuyo resultado se perdió no se repiten nunca: al agente se le dice que el desenlace es desconocido, que es lo honesto y evita mandar dos veces el mismo mail.

Los reanudados automáticos tienen tope (KERNEL_AGENT_RESUME_WINDOW_MS, KERNEL_AGENT_MAX_AUTO_RESUMES), para que un run que tira abajo el kernel no lo tire abajo en cada arranque.

El mundo 3D

El dashboard abre directamente en el mundo, con una pestaña Oficinas al lado que lista cada una con su estado. Las oficinas nuevas se construyen en lotes fijos: crear, agrandar o borrar una nunca mueve a las demás, y los lotes libres muestran un cartel de "Lote disponible" en el que podés hacer clic para abrir el asistente. Si creás una oficina con el mundo abierto, la ves levantarse: una cuadrilla arma las paredes y después llegan los agentes a sus escritorios.

Las extensiones pueden aportar su propio edificio al mundo. En la captura de arriba, el Warehouse de la derecha es eso.

Ocho arreglos de seguridad

Los que más pesan:

  • Una herramienta de workspace tomaba la oficina del llamador de un argumento. Un flow_id explícito pisaba la identidad, así que cualquier agente podía alcanzar los workspaces privados de otra oficina.
  • Las credenciales de los forges se guardaban en texto plano (GitHub, GitLab, Gitea), incluidas las claves privadas de GitHub App. Ahora se cifran.
  • POST /api/comms/inbound fallaba abierto: sin token configurado aceptaba cualquier correo. Ahora responde 503 hasta que lo definas.
  • Las claves y cookies de Twitter/X se mandaban al dashboard en cada listado de cuentas.
  • El sandbox de Docker fallaba abierto: una allowlist de egreso inválida dejaba la red abierta en silencio. Y los procesos sandboxeados ya no heredan el entorno y los secretos del kernel.

Lo que te va a romper al actualizar

Esto es lo que conviene leer antes, no después:

  • Sin TIMEZONE, el kernel usa la zona horaria de la máquina, no UTC. Mueve más que el "hoy": los agentes programados corren en esa hora local. Uno con 0 8 * * * corría a las 08:00 UTC y pasa a correr a las 08:00 tuyas. Poné TIMEZONE=UTC para dejarlo como estaba.
  • Los recordatorios y eventos sin zona horaria son hora local. 2026-03-01T09:00 no significaba nada definido antes; ahora son las 09:00 de tu TIMEZONE.
  • Definí KERNEL_ENCRYPTION_KEY antes de actualizar si usás conexiones a GitHub, GitLab o Gitea, y guardala. Perderla después vuelve ilegibles esos tokens.
  • Issues desapareció: la página, su pestaña, su extensión y las herramientas kernel_issues_* salieron del core. Los issues sincronizados siguen en la base, pero nada los lee.
  • El stack de Docker arranca el motor realtime y el puente de WhatsApp por defecto, así que un docker compose up común se baja dos imágenes más.

Cómo actualizar

curl -fsSL https://lifekernl.com/install.sh | sh

El mismo comando instala y actualiza. En macOS y Windows el update se hace desde la app, con el botón "Update now". El detalle completo está en el CHANGELOG, y los binarios para rpm, deb, dmg y msi salen en la página del release.

Registro de cambios

Actualizar desde 0.3.2

  • Sin TIMEZONE, el kernel ahora usa la zona horaria de esta máquina, no UTC. En una Mac es tu propia zona; en un contenedor sigue siendo UTC. Esto mueve más que el "hoy": los agentes programados corren a esa hora local (un agente configurado en 0 8 * * * corría a las 08:00 UTC y ahora corre a las 08:00 tuyas). Poné TIMEZONE=UTC si querés el comportamiento anterior.
  • Las horas de recordatorios y eventos sin zona son hora local. 2026-03-01T09:00 antes no significaba nada concreto (los recordatorios lo comparaban como si fuera UTC); ahora es las 09:00 en TIMEZONE. Los recordatorios y eventos existentes guardados así se reescriben como instantes UTC en el primer arranque, interpretados de la misma manera. Las horas con Z o con offset no cambian.
  • Configurá KERNEL_ENCRYPTION_KEY antes de actualizar si usás conexiones de GitHub, GitLab o Gitea, y no la pierdas. Sus tokens y las claves privadas de las GitHub Apps se guardaban en texto plano; con una clave configurada se cifran en el primer arranque. Si después cambiás o perdés la clave, quedan ilegibles: tenés que volver a agregar la conexión. Sin clave quedan como estaban.
  • Crear un contacto con un teléfono o email que ya existe lo fusiona con ese contacto en vez de agregar un duplicado, por cualquier camino (tool, RPC, HTTP): ahora pasa por el mismo servicio que la tool MCP.
  • Borrar una tarea por HTTP ahora es un borrado lógico, igual que en todos lados; una tarea borrada ya no aparece en la lista del dashboard.
  • El email entrante (POST /api/comms/inbound) necesita COMMS_INBOUND_TOKEN, enviado en el header X-Inbound-Token. Un relay que mandaba ?token= o que dependía de que el token no estuviera configurado deja de entregar hasta que lo actualices.
  • Un body de request vacío o mal formado da 400 (413 si pasa los 10 MB) en la API HTTP, donde la mayoría de las rutas respondían 500. Algunos mensajes de 500 ahora dicen Error: ….
  • Issues ya no existe. La página de Issues, su pestaña en el menú Work, su extensión y las tools kernel_issues_* se sacaron del core. Los agentes o scripts que llamaban a esas tools dejan de encontrarlas. Los issues sincronizados quedan en la base, intactos, pero ya nada los lee.
  • El stack de Docker ahora levanta por defecto el motor de tiempo real (mtw-request) y el bridge de WhatsApp. Ya no necesitan --profile torrents, y BRIDGE_ENABLED y RUST_BRIDGE_ENABLED vienen en true por defecto. Un docker compose up pelado baja dos imágenes más y crea los volúmenes mtw-torrents, mtw-whatsapp-sock y mtw-whatsapp-data. Las descargas de torrents ahora viven en un volumen, así que recrear el contenedor las conserva. Poné las dos variables en false para quedarte con el stack anterior, solo con el kernel.
  • Las carpetas del host pasaron a un overlay opcional, docker-compose.host.yml. El docker-compose.yml por defecto ya no monta carpetas del host en el kernel (antes montaba una ruta fija). Si navegás una carpeta del host con el Filesystem Commander, o corrés agentes claude_code con tu login de Claude Code (ahora montado en lectura-escritura para que el CLI pueda renovar su sesión), configurá KERNL_FS_ROOT en .env y agregá -f docker-compose.host.yml a cada comando docker compose del stack. HOST_HOME ahora toma por defecto tu $HOME.
  • La voz está activada salvo que pongas VOICE_ENABLED=false. Los motores por defecto son locales y gratis (whisper.cpp para escuchar, Piper para hablar). Las variables viejas siguen andando: VOICE_STT_PROVIDER=local-whisper significa whisper.cpp, y VOICE_TTS_PROVIDER=system pasa a ser auto. La voz de Piper en español (unos 110 MB) se descarga en el volumen de datos la primera vez que se usa.
  • Si elegís para un agente de Claude Code un modelo que no es de Claude, el agente pasa al executor propio del kernel. Antes la elección se guardaba pero nunca se usaba, y cada corrida fallaba en su primer turno.

Agregado

  • ECC como fuente de skills por defecto. El catálogo del marketplace ahora se suscribe a affaan-m/ECC (MIT, ~290 skills), fijado en v2.2.1. Solo se agrega la suscripción: no se instala ninguna skill. Se agrega una vez por base de datos, así que si te desuscribís, queda así. El catálogo se llena en la próxima sincronización de repos (cada 6 horas, o con "Sync" en el marketplace).
  • El canal del agente principal corre con cualquier modelo conectado, con un selector de modelo en su encabezado; los proveedores sin sesión siguen en el menú, atenuados, con el motivo.
  • El progreso de la actualización se ve en el banner, no solo en Settings → About.
  • La búsqueda de trabajo es una extensión (automation/job-hunter), instalada y activa por defecto; sus handlers conservan los nombres, así que los agentes existentes siguen andando.
  • El dashboard abre en el mundo 3D, que aparece antes que Offices. Una nueva pestaña Offices al lado lista todas las oficinas con su estado. Pasar de una a otra no recarga el mundo.
  • Las extensiones pueden sumar sus propios edificios al mundo 3D. Una extensión que declara un world plugin (incluidas las pagas) recibe un lote en el terreno y dibuja ahí su edificio.
  • Las oficinas nuevas se construyen en lotes fijos. Crear, agrandar o borrar una oficina nunca mueve otra. Los lotes libres muestran un cartel de "Lote disponible", y al hacer clic en uno se abre el asistente de nueva oficina. Una oficina creada con el mundo abierto se construye en pantalla: una cuadrilla levanta las paredes y después los agentes llegan a sus escritorios. Podés saltear la animación.
  • Proyectos. Una oficina puede atender varios productos o negocios. Las corridas, la memoria, los aprendizajes, las cartas y las programaciones pertenecen a un proyecto. En una corrida de proyecto, las tools que publican o envían algo escriben en cambio un borrador en una bandeja de salida, y no sale nada hasta que lo aprobás. Los borradores aprobados salen por email, newsletter, WhatsApp o LinkedIn. Se respetan las marcas de no contactar y los links de desuscripción. Un proyecto puede conectar sus propios datos con un pull de snapshot y webhooks firmados (docs/project-connector-v1.md). Las aprobaciones pendientes se ven en el resumen de Work.
  • Los agentes pueden buscar negocios en Google Maps una vez que guardás una API key de Google Places en Settings → Integrations.
  • Hablale al Chief. Un botón de micrófono en el chat y en el canal del Chief, con respuestas habladas que podés activar, más notas de voz en Telegram. El reconocimiento de voz y la voz se configuran en Settings → AI → Voice, con una prueba de micrófono. El reconocimiento puede usar whisper.cpp, Groq u OpenAI; la voz puede ser Piper, OpenAI o ElevenLabs.
  • Conectá un buzón desde Settings o desde el asistente de configuración. El proveedor se detecta a partir de la dirección, IMAP y SMTP se prueban antes de guardar, y la tarjeta te guía con las contraseñas de aplicación cuando el proveedor las pide. Las cuentas conectadas se listan con el estado de sincronización y la cantidad de no leídos, y cada una enlaza a su buzón.
  • Correo IMAP en la vista de mail. Los mensajes se decodifican, los cuerpos HTML se muestran con las imágenes remotas bloqueadas, y cada cuenta muestra su estado de sincronización. Las cuentas de Gmail se dividen en las pestañas Principal, Notificaciones, Promociones, Social y Foros.
  • La clasificación y el análisis de mail pueden correr en un proveedor elegido (comms.llm.provider, opcionalmente comms.llm.model). Si ese proveedor falla o está desconectado, toma la posta la cadena por defecto.
  • Vinculá WhatsApp desde Settings o desde el asistente de configuración con un código QR o un código de teléfono. La sesión sobrevive a las actualizaciones, así que no te va a pedir que escanees el QR de nuevo.
  • Los paquetes nativos traen el motor de tiempo real y el bridge de WhatsApp. Las instalaciones de Linux, macOS y Windows (MSI y zip) los supervisan como sidecars; en Windows se comunican por named pipes.
  • Uso de tokens por modelo, por llamador y por día en Settings → AI → Token usage. Se cuenta cada llamada a un modelo, incluidas las de la suscripción de Claude Code y las corridas de agentes, que antes no se contaban. Los modelos cuyo proveedor no informa costo se valúan con la tabla de precios de LiteLLM.
  • Las corridas de agentes interrumpidas se retoman. Una corrida cortada por un reinicio sigue desde donde quedó. Las llamadas a tools cuyo resultado se perdió nunca se repiten; al agente se le avisa que su resultado es desconocido. Las corridas más viejas se pueden retomar a mano (kernel_agents_resume). Los reintentos automáticos tienen tope (KERNEL_AGENT_RESUME_WINDOW_MS, KERNEL_AGENT_MAX_AUTO_RESUMES), así que una corrida que tira el kernel no puede tirarlo en cada arranque. Las corridas también registran condiciones (modelo listo, interrumpida, retomada, abortada) con un motivo.
  • Workspaces de oficina declarativos. Una oficina puede declarar qué tiene que haber en su carpeta: repos de git para clonar, archivos para sembrar, y los servidores MCP y las skills que comparten sus agentes de Claude Code (kernel_agents_workspace_apply). Antes de cada corrida la carpeta se pone al día con esa especificación. Los checkouts existentes nunca se resetean, y una corrida cuya carpeta no se puede preparar falla con el motivo.
  • Los agentes de una oficina pueden consultarle al Chief. El Chief responde lo que puede y te pasa el resto en My Office. Los agentes que no responden cuando un colega les escribe se vuelven a despertar hasta que acusan recibo de la carta.
  • La oficina del Chief muestra lo que te necesita. Las fallas se agrupan y se explican, y las resueltas quedan marcadas. Cada una se puede arreglar con un clic o pasársela al Chief. Lo que descartás queda recordado.
  • El Chief puede reportar bugs del propio Kernl. Los bugs aparecen en una pestaña de My Office con el contexto de la corrida censurado. Un bug se convierte en issue de GitHub solo después de que lo aprobás.
  • Los pedidos de permiso de tools se muestran en línea en el canal del Chief y en el chat, con "Permitir todo" para el resto de la sesión.
  • Un panel de agente rediseñado. Las pestañas Overview y Settings quedan bajo un encabezado de una línea. El modelo se cambia desde un chip en el encabezado. Correr y frenar usan el mismo botón, y la programación es un switch de encendido/apagado. El mandato se abre por defecto, renderizado como markdown. Al pasar el mouse sobre una skill se explica qué hace, traducido por el modelo externo más barato.
  • Pestañas LIVE e HISTORY legibles. Cada paso muestra la llamada al lado de su resultado, y cada fila se abre con el detalle completo. Las llamadas idénticas repetidas se agrupan en una sola entrada "×N", y las fallidas quedan marcadas. Cuando un agente actúa sobre otro agente, el paso se muestra como una tarjeta con el destinatario y el resultado.
  • El mundo 3D cobra vida. Las cartas entre colegas vuelan de escritorio en escritorio. Los comandos del Chief nombran al agente al que apuntan. Al hacer clic en una mesa de reunión se ve en qué están trabajando los dos agentes que están ahí.
  • Cambios visuales en el mundo 3D. Hay una capa opcional de realismo fotográfico. Se rediseñaron la recepción, la sede central y la oficina de DevOps, el lobby tiene alfombra mate, y los agentes entran por la puerta. Las placas de los racks de DevOps abren el repo.
  • El resumen de Social muestra lo que necesita atención en mail, contactos e IRC. Su menú queda solo con Overview, Mail, Contacts e IRC.
  • La configuración de las extensiones puede ofrecer las cuentas de mail de Kernl como opciones.
  • Una compra pendiente en la tienda se puede retomar o cancelar. Antes, cerrar la pestaña de Stripe dejaba la tarjeta en "Esperando el pago" hasta 24 horas.
  • La licencia va primero en Settings. Una licencia pegada se guarda en un solo paso, y se acepta una licencia copiada de un email en el que los saltos de línea se convirtieron en espacios.
  • Los chats nuevos arrancan con el último modelo que elegiste en un chat.

Corregido

  • Un proveedor sin cuota podía cortar el fallback al siguiente. Cuando no se podía escribir la tabla que recuerda los proveedores agotados, el error se escapaba y la corrida fallaba en vez de seguir; ahora esa escritura es best effort y el fallback continúa.
  • No se podía conectar Claude Code desde la app de macOS. El .dmg no traía el CLI claude, así que el paso de inicio de sesión mostraba un claude pelado que respondía "command not found", y no había forma de usar una suscripción Pro o Max. Ahora el CLI viene dentro de la app, como ya pasaba en Windows, y el comando de inicio de sesión, el proveedor del chat y los agentes corren todos el mismo binario.
  • Se perdían las respuestas largas en Discord y Telegram. Las plataformas rechazan un mensaje de más de 2000 / 4096 caracteres y nada lo partía; ahora las respuestas se dividen en límites de párrafo, línea o palabra, dejando intactos los bloques de código.
  • Las páginas de extensiones perdían el texto del contenido sanitizado (ítems de RSS, noticias, cuerpos e hilos de email): el sanitizador compartido eliminaba los nodos de texto.
  • Una escritura lenta del dashboard podía ejecutarse dos veces. Cuando el WebSocket andaba lento, el dashboard también mandaba el request por HTTP, así que un "Run", "Create" o "Publish" lento podía ejecutarse dos veces. Ahora las escrituras van por un solo camino, y un error que respondió el kernel no se reintenta.
  • Los dos caminos del dashboard respondían distinto. Cada acción accesible por RPC sobre WebSocket y por HTTP ahora corre una sola función. Entre lo que eso arregló: "Run now" por WebSocket dejaba {{event.*}} en el objetivo y se salteaba el circuit breaker; las actualizaciones de agentes por WebSocket perdían campos como wake-on-inbox; el chat por WebSocket perdía los adjuntos; los feeds de las columnas de noticias y el mapa de arquitectura nunca anduvieron por WebSocket; las fallas se mostraban como éxito.
  • La búsqueda de alimentos fallaba siempre (nutrición, incluida la tool MCP).
  • Otros arreglos encontrados durante la unificación: un feed RSS no se podía desactivar por WebSocket; las acciones de la página de entrenamiento nunca llegaban al kernel por WebSocket; quitar un ítem de la lista de compras por HTTP respondía 404; borrar un contacto con interacciones fallaba; crear un recurso de aprendizaje sin todos los campos fallaba; un #tag en la búsqueda de notas era un error de sintaxis; una transacción de finanzas guardaba un monto con signo pero movía el saldo por su valor absoluto; GET /api/agents/:id/memory ignoraba ?limit=; revocar el inicio de sesión de un servidor MCP nunca hacía nada; el fallback del estado de Google consultaba el endpoint equivocado.
  • Un borrador de oficina que no pasa la validación tiene un intento de reparación, y el error nombra al modelo que falló.
  • "Hoy" era el día UTC. En UTC-3 pasaba a ser mañana a las 21:00: el briefing de la mañana, las tareas que vencen hoy y las vencidas, el calendario, la agenda, los conteos de "completadas hoy" y la fecha que se les informa a los agentes cambiaban antes de tiempo, y un evento o recordatorio de la noche aparecía en el día siguiente. Ahora cada límite de día sigue a TIMEZONE, y las horas en briefings y notificaciones se muestran en esa zona.
  • Un recordatorio diario o semanal se corría una hora en cada cambio de horario de verano; ahora mantiene su hora local. /remind … at 9am significaba las 09:00 en la zona del servidor (UTC en un contenedor); ahora significa en la tuya.
  • Un recordatorio que vencía más temprano hoy no contaba como vencido en /status ni en los briefings hasta el día siguiente (su hora se comparaba como texto contra un "ahora" con otro formato).
  • Listar eventos hasta una fecha dejaba afuera los eventos de ese día.
  • Una migración que fallaba a la mitad quedaba aplicada a medias, sin registrarse, y volvía a correr en el próximo arranque sobre el esquema parcial. Ahora cada migración se aplica entera o no se aplica.
  • Las tools aceptaban cualquier limit. 37 tools pasaban un limit sin tope directo a SQL; ahora tiene un tope por tool (un valor mayor se recorta, no se rechaza). Los argumentos de tools con valor por defecto ya no figuran como obligatorios, y los argumentos .optional().default() se publican con su tipo real.
  • System → Processes decía siempre "System registry not available". La página nunca se suscribía al canal que lee, y el canal no incluía el flag available que la página espera.
  • La página de una campaña no mostraba destinatarios; ahora lista cada uno con su estado y error, y cuenta enviados, fallidos y pendientes.
  • La configuración de los canales se abría vacía. Los formularios de WhatsApp y de canal genérico leían un campo que nadie mandaba; ahora muestran la configuración guardada, con los campos de contraseña enmascarados.
  • Crear, pausar o cancelar una suscripción podía no hacer nada sin avisar cuando la conexión en vivo estaba caída; ahora cae a HTTP.
  • Una corrida que fallaba antes de arrancar quedaba "activa" para siempre (sin tools, sin proveedor utilizable): ahora siempre se saca de las corridas activas.
  • El reset de rate limit de 750ms de un proveedor se leía como 750 minutos, y por eso esperaba el tope de 15 segundos. Ahora se entienden milisegundos y horas.
  • Las credenciales de Google guardadas desde el dashboard nunca se leían, así que vincular Gmail siempre decía "credentials not configured". Ahora la configuración guardada se aplica al arrancar, antes de que inicie cualquier módulo, y guardar tiene efecto sin reiniciar. Las variables de entorno reales siguen teniendo prioridad.
  • La clasificación de emails fallaba en cada lote con modelos de razonamiento. Se quedaban sin tokens a mitad del razonamiento, o un corchete en su razonamiento rompía el parseo.
  • La bandeja de mail se quedaba en "Loading" después de elegir una cuenta. Una acción que la conexión en vivo no conoce ahora cae a HTTP.
  • Una licencia rechazada reemplazaba a la que funcionaba. Ahora la licencia actual sigue activa cuando se rechaza una pegada.
  • El resultado de una tool podía quedar etiquetado con la tool equivocada cuando un turno hacía dos llamadas (por ejemplo, una actualización de agente mostrada como salida de ToolSearch).
  • El lanzador portable de Linux fallaba cuando se iniciaba a través de un symlink en el PATH.
  • Un agente abierto en la pestaña History desde un link no mostraba corridas.
  • El Chief se reportaba a sí mismo, entrando a My Office para entregar su propio reporte.
  • Los eventos en vivo de los agentes se mostraban dos veces, y en el mundo 3D se podían dejar dos paquetes en el mismo lugar.

Seguridad

  • Una tool de workspace ya no toma la oficina del llamador de un argumento. Un flow_id explícito pisaba la identidad del llamador, así que cualquier agente podía llegar a los workspaces privados de otra oficina. Los agentes CLI, cuya identidad llega con el request, ahora también reciben su propia oficina.
  • Los adjuntos y los streams de chat respondían Access-Control-Allow-Origin: *. Ahora siguen la allow-list de CORS opcional del servidor. Los adjuntos HTML y SVG se descargan en vez de renderizarse en línea desde el origen del kernel.
  • Las credenciales de las forjas se cifran en reposo (ver Actualizar). Una conexión cuyas credenciales no puede abrir la clave actual se marca como ilegible, lo indica en su prueba y en el listado, y nunca se envía a la forja.
  • POST /api/comms/inbound fallaba abierto. Sin COMMS_INBOUND_TOKEN aceptaba cualquier email; ahora responde 503 hasta que se configura el token, lo acepta solo en el header X-Inbound-Token (ya no en ?token=), y lo compara en tiempo constante.
  • Las API keys, tokens y cookies de Twitter/X se mandaban al dashboard en cada listado de cuentas. Ahora van enmascarados; si dejás una credencial en blanco al editar, se conserva la guardada. La configuración de los canales enmascara sus secretos de la misma forma.
  • Las actualizaciones de comms escribían cualquier columna que nombrara el llamador. Ahora el servicio aplica su propia allow-list de columnas.
  • El sandbox de Docker falla cerrado. Se rechaza una allowlist de salida o un nombre de red inválido; antes, dejaba la red abierta sin avisar. Los procesos de agentes en sandbox ya no heredan el entorno ni los secretos del kernel.
  • Las especificaciones de workspace rechazan entradas inseguras. Se rechazan las rutas fuera del workspace, y las URLs de repos o branches que git podría interpretar como opciones.
  • /api/comms/unsubscribe/ es accesible sin el token de la API, porque la gente que hace clic en los links de desuscripción no lo tiene.

Cambiado

  • Una gran reestructuración interna sin cambios de comportamiento buscados más allá de lo anterior: un único helper de rutas HTTP, una operación por acción del dashboard, tools tipadas y factories de módulos en el SDK de extensiones, plomería compartida de canales y forjas, el executor de agentes dividido en fases, un único loop de reintento y fallback en la capa de LLM, una única librería de frontend compartida por el dashboard y las páginas de extensiones, fuentes de calendario aportadas por los módulos dueños de cada una, y entry points de extensiones generados.

Eliminado

  • Issues (página, extensión, tools) y la página de analytics de contactos que no se usaba. Ver Actualizar.