Durante años hemos construido interfaces bajo una suposición casi invisible: un equipo humano decide de antemano qué pantallas, tablas, formularios, botones y gráficos existirán. La aplicación puede recibir datos dinámicos, pero su repertorio visual suele estar diseñado antes de que el usuario llegue.

Los agentes de IA hacen posible invertir esa relación.

En vez de programar todas las vistas por anticipado, podemos imaginar una aplicación donde el usuario describe una necesidad, un modelo genera la interfaz apropiada para esa tarea y el sistema la ejecuta de forma controlada. Esa idea suele llamarse generative UI o interfaz generativa.

ArrowJS resulta interesante precisamente porque intenta convertir esa idea en una arquitectura concreta. El proyecto se presenta como “the first UI framework for the agentic era” y combina dos propuestas distintas:

  1. un framework de UI extremadamente pequeño y cercano a JavaScript/TypeScript;
  2. un sandbox para ejecutar lógica de UI generada dinámicamente sin darle al código del modelo acceso directo al entorno privilegiado de la aplicación.

La segunda propuesta es la realmente novedosa.

El artículo de KDnuggets “Is ArrowJS Really the UI for the Agentic Era?” popularizó recientemente esta idea. Pero al mirar la documentación oficial y proyectos experimentales construidos alrededor de Arrow aparece una imagen más interesante que la de “otro framework frontend”.

Primero: ArrowJS intenta ser fácil para humanos y para agentes

El núcleo de Arrow gira alrededor de una API pequeña basada en primitivas normales de TypeScript. La documentación destaca tres funciones principales:

reactive
html
component

No necesita JSX y puede utilizar template literals nativos. Tampoco obliga a introducir una fase de compilación específica del framework para el caso básico.

Un contador mínimo tiene una forma parecida a esta:

import { html, reactive } from '@arrow-js/core'

const state = reactive({ count: 0 })

export default html`
  <button @click="${() => state.count++}">
    Count: ${() => state.count}
  </button>
`

Para un humano esto reduce conceptos adicionales. Para un coding agent también tiene una ventaja: hay menos sintaxis y menos reglas específicas del framework que recordar.

Arrow incluso enfatiza que su documentación completa ocupa una fracción pequeña de una ventana de contexto grande. La tesis implícita es importante: un framework que un agente puede cargar y razonar casi por completo puede producir menos errores que uno cuya semántica depende de una enorme colección de convenciones, compiladores, plugins y excepciones históricas.

Eso no demuestra que Arrow produzca mejor código que React en la práctica. React tiene una ventaja gigantesca en ejemplos, ecosistema, bibliotecas y datos de entrenamiento. Pero sí plantea una pregunta válida: ¿deberíamos seguir diseñando frameworks exclusivamente para desarrolladores humanos cuando una parte creciente del código será escrita por agentes?

La pieza decisiva: @arrow-js/sandbox

Aquí es donde ArrowJS se vuelve mucho más interesante.

La documentación oficial de @arrow-js/sandbox explica que sandbox() crea un elemento host estable y arranca detrás de él una VM QuickJS + WASM. El código no confiable se ejecuta dentro de esa VM, mientras que el host conserva el control del DOM real.

Conviene precisar esto porque a veces se simplifica diciendo que Arrow “compila la UI a WebAssembly”. Esa descripción puede inducir a error. El modelo mental más útil es:

Código JS/TS generado
        │
        ▼
QuickJS dentro de una VM basada en WASM
        │
        ▼
protocolo/control de render
        │
        ▼
DOM real controlado por el host

El código generado no necesita recibir acceso directo al window privilegiado de la aplicación para producir una interfaz inline.

Ese detalle separa la idea de dos alternativas problemáticas:

  • ejecutar texto generado por un LLM con eval() en la página principal;
  • meter cada interfaz generada en un iframe completamente separado y aceptar sus limitaciones de integración.

Arrow intenta ocupar un punto intermedio: aislar la lógica, pero renderizar una experiencia integrada.

El host bridge: capacidad, no autoridad ilimitada

Una interfaz generada se vuelve útil cuando puede consultar datos o ejecutar acciones. Pero ahí aparece la pregunta de seguridad: ¿qué puede hacer exactamente?

Arrow permite que el host exponga módulos explícitos mediante un host bridge.

Por ejemplo:

sandbox(
  { source: generatedCode },
  {},
  {
    'host-bridge:app': {
      getFailedJobs,
      retryJob
    }
  }
)

Dentro del sandbox, el código generado puede importar únicamente aquello que el host decidió publicar:

import { getFailedJobs, retryJob } from 'host-bridge:app'

La idea de seguridad no es “confiamos en que el modelo se comporte”. Es otra:

El código generado recibe capacidades concretas, no autoridad general sobre la aplicación.

Si el host no expone acceso al filesystem, credenciales, cookies, SSH, GitHub o una API interna, la interfaz no debería poder inventarse esas capacidades por sí sola.

Este patrón recuerda a capability-based security: poseer una referencia explícita a una operación es lo que permite solicitarla.

Ejemplo 1: una búsqueda que el agente diseña en el momento

Supongamos que el usuario escribe:

Busca recetas rápidas para cenar y déjame elegir una.

Una aplicación tradicional necesita tener programada una pantalla RecipeSearch, probablemente con su caja de búsqueda, estados de carga, tabla o tarjetas y botón de selección.

En un sistema de UI generativa el flujo puede ser distinto:

Usuario
  │
  ▼
LLM
  │ genera Arrow/TypeScript
  ▼
Sandbox
  │
  ├─ caja de búsqueda
  ├─ loading
  ├─ resultados
  └─ botón "Elegir"
  │
  ▼
Host tools permitidas
  ├─ searchRecipes(query)
  └─ chooseRecipe(id)

El modelo decide que una lista de tarjetas es la mejor representación. Pero la operación de buscar recetas sigue siendo responsabilidad del host.

Eso permite que la aplicación controle autenticación, rate limits, acceso a datos y validación sin programar de antemano cada variante visual.

Summon: un experimento real construido alrededor de esta idea

Un proyecto especialmente útil para entender hasta dónde puede llegar este patrón es Block Summon.

Summon se describe como un sistema para renderizar AI-generated UI in an inline Arrow sandbox. Su arquitectura separa explícitamente varios conceptos:

Surface       = UI generada
Host tool     = dato o acción propiedad del host
Sandbox       = runtime aislado de Arrow
SurfacePolicy = lo que esa UI tiene permiso para solicitar
Diagnostics   = trazas y eventos para depurar el proceso

Su quickstart incluye escenarios de búsqueda respaldada por tools del host, acciones, formularios, trabajo en background y flujos que necesitan aprobación.

Hay un detalle importante sobre el estado del proyecto. El README todavía habla de beta y desarrollo activo, pero el repositorio de GitHub aparece actualmente marcado como archivado, y los últimos commits visibles son de junio de 2026. Por tanto, Summon conviene verlo como un experimento arquitectónico muy útil, no como una dependencia que debamos asumir activa para producción.

Aun así, demuestra que el patrón puede ir bastante más lejos que un contador generado.

Ejemplo 2: publicar requiere aprobación

Imaginemos una aplicación editorial. El usuario pide:

Revisa este borrador, resume sus datos y déjame publicarlo si todo está bien.

El agente puede generar una surface como:

┌──────────────────────────────────┐
│ Article ready                    │
│                                  │
│ 842 words                        │
│ 3 references                     │
│ SEO score: 91                    │
│                                  │
│ [ Edit ]             [ Publish ] │
└──────────────────────────────────┘

Pero que el modelo haya generado un botón llamado Publish no significa que posea permiso para publicar.

La arquitectura correcta mantiene la división:

Generated UI
     │
     │ solicita publish(articleId)
     ▼
Host policy
     │
     ├─ valida parámetros
     ├─ comprueba permiso
     ├─ solicita aprobación humana
     └─ usa credenciales reales
     │
     ▼
Backend

Una regla conceptual muy útil es:

Generative UI no debe equivaler a generative authority.

La interfaz puede proponer y solicitar. La autoridad permanece en código confiable.

Ejemplo 3: un dashboard de operaciones generado para la pregunta actual

Pensemos en un sistema de procesamiento como un pipeline de publicación de podcasts.

El operador pregunta:

¿Qué publicaciones fallaron desde anoche y cuáles puedo reintentar?

Una respuesta textual puede listar veinte jobs. Pero quizá el mejor artefacto para esa pregunta sea una interfaz temporal:

Publicaciones fallidas

┌────────────────────────┬──────────┬─────────────┐
│ Job                    │ Error    │ Acción      │
├────────────────────────┼──────────┼─────────────┤
│ episodio-481           │ timeout  │ [ Retry ]   │
│ episodio-482           │ auth     │ [ Details ] │
│ episodio-483           │ timeout  │ [ Retry ]   │
└────────────────────────┴──────────┴─────────────┘

2 parecen recuperables

[ Retry recoverable jobs ]

Nadie necesitó crear previamente un componente llamado FailedPublicationDashboard.

El agente recibió datos y capacidades como:

get_failed_publications()
retry_publication(id)

Y decidió cómo convertir esa información en una interacción útil.

Este caso ilustra por qué la UI generativa puede ser más importante en herramientas internas que en páginas públicas. Los operadores realizan consultas muy específicas y cambiantes. Programar una pantalla para cada pregunta posible no escala.

Ejemplo 4: la interfaz cambia a medida que cambia la conversación

Aquí aparece una posibilidad todavía más radical.

Primero el usuario pregunta:

¿Están vivos mis ocho workers?

El agente responde con ocho tarjetas.

Después:

Compáralos por throughput durante las últimas 24 horas.

La mejor representación ya no son tarjetas: quizá sea un gráfico de barras.

Y luego:

Enséñame solamente los dos anómalos y déjame inspeccionar sus errores.

La UI puede transformarse otra vez en una tabla de diagnóstico.

cards
  ↓
chart
  ↓
diagnostics table
  ↓
worker inspector

La idea profunda es que la interfaz deja de ser solamente el contenedor del diálogo y pasa a ser una modalidad de respuesta del modelo.

Hoy un LLM puede devolver texto, código, JSON o tool calls. En una aplicación agentic-first podría devolver también una interfaz interactiva específica para la tarea.

¿Dónde encajan MCP y WebMCP?

La combinación natural es separar capacidades de presentación.

MCP o mecanismos parecidos pueden describir qué herramientas y recursos existen:

search_jobs
get_worker_metrics
retry_job
publish_article

Arrow puede encargarse de la superficie visual que consume esas capacidades.

El modelo mental sería:

Usuario
   │
   ▼
Agente / LLM
   │
   ├── decide qué tools usar
   │
   └── genera la UI apropiada
              │
              ▼
        Arrow sandbox
              │
              ▼
      tools controladas por host
              │
              ▼
      servicios / datos reales

Las tools definen lo que se puede hacer. La UI generativa decide cómo presentarlo en ese momento.

El sandbox no elimina todos los riesgos

Sería un error concluir que WASM convierte automáticamente en seguro cualquier código generado.

Todavía hay que defender múltiples fronteras:

  • schemas y argumentos de las tools;
  • permisos por usuario y por acción;
  • límites de CPU, memoria y tiempo;
  • outputs gigantes o interfaces que intenten confundir al usuario;
  • phishing visual dentro de la propia aplicación;
  • acciones sensibles disfrazadas de botones inocentes;
  • persistencia y replay de surfaces generadas;
  • cambios de contrato entre una UI guardada y las tools actuales.

Summon tenía incluso un escenario adversarial dedicado a comprobar intentos de acceso a network, storage, contexto padre y tools no autorizadas. Eso revela algo importante: el problema de seguridad de generative UI no termina en aislar JavaScript.

La UI también es una superficie de autoridad y persuasión.

¿Entonces ArrowJS reemplaza a React?

No es la conclusión más razonable hoy.

React conserva ventajas enormes:

  • ecosistema;
  • librerías y design systems;
  • contratación;
  • tooling;
  • años de documentación;
  • una cantidad masiva de ejemplos dentro de los datos de entrenamiento de los modelos.

Además, los agentes mejoran. Es posible que parte del argumento “los frameworks complejos son difíciles para LLMs” sea temporal. Modelos futuros pueden manejar hooks, JSX y toolchains con una fiabilidad que reduzca la ventaja de una API minúscula.

Pero eso no invalida el segundo argumento de Arrow.

React puede ser excelente para que un agente escriba código normal y aun así no resolver por sí mismo el problema de ejecutar UI no confiable generada bajo demanda con una frontera explícita de capacidades.

Son problemas distintos.

Dos tesis que conviene separar

ArrowJS se puede evaluar desde dos perspectivas:

A) Framework amigable para coding agents

   Codex / Claude / otro agente
              │
              ▼
       escribe aplicación
              │
              ▼
           ArrowJS

Y:

B) Runtime para generative UI

   Usuario
      │
      ▼
     LLM
      │ genera UI
      ▼
QuickJS/WASM sandbox
      │
      ▼
 host tools limitadas

La tesis A es interesante, pero compite directamente contra ecosistemas gigantes.

La tesis B es más novedosa. Plantea una arquitectura donde el modelo puede fabricar la interfaz necesaria para una tarea sin recibir control general sobre la aplicación.

Una arquitectura que vale la pena experimentar

No sabemos todavía si ArrowJS será el framework que popularice este patrón. El ecosistema sigue siendo pequeño y uno de los experimentos más interesantes construidos sobre él, Summon, ya está archivado.

Pero la pregunta que Arrow pone sobre la mesa probablemente sobrevivirá al framework:

Si un agente puede decidir qué información necesita, qué tools llamar y qué pasos ejecutar, ¿por qué la interfaz que utiliza el usuario debe estar completamente predeterminada?

La respuesta puede ser una nueva capa en las aplicaciones agentic-first:

LLM
 │
 ├── texto cuando basta texto
 ├── tool calls cuando necesita actuar
 └── UI generada cuando la tarea necesita interacción

El reto no consiste simplemente en permitir que el modelo genere HTML.

Consiste en conseguir simultáneamente tres propiedades:

flexibilidad de UI
       +
aislamiento del código generado
       +
autoridad controlada por el host

ArrowJS es interesante porque intenta juntar precisamente esas tres piezas.

Fuentes y lecturas complementarias