La criatura ya no hace cola: dynamic workflows y el salto de la cadena al grafo

Claude Code escribe el guion de orquestación, lanza una flota de subagentes y la coordinación no cuesta ni un token. Tercera entrega de la serie: del bucle al grafo que se ejecuta solo.

Le dimos un bucle y vació el backlog. Le dimos un grafo y dejó de olvidar. Ahora el grafo se ejecuta solo: Claude Code escribe el guion de orquestación, lanza una flota de subagentes y la coordinación no cuesta ni un token. Tercera entrega de la serie, y la que cierra el círculo.

Esta serie empezó con un bucle. La criatura que vaciaba tu backlog mientras dormías era, mirada de cerca, homeostasis con GPU: reúne contexto, actúa, verifica, repite. Después vino el grafo, cuando quedó claro que el agente olvida y el grafo no y sacamos la memoria fuera de la ventana de contexto.

Hoy toca el tercer movimiento, y es distinto de los dos anteriores. El grafo deja de ser un dibujo y pasa a ser el programa. No un diagrama en la pizarra que describe cómo debería fluir el trabajo, sino un script que lo ejecuta: nodos que piensan, aristas que transportan resultados y un runtime que despliega la flota mientras tu sesión sigue libre para otra cosa.

La herramienta se llama dynamic workflows y viene integrada en Claude Code desde finales de mayo. Pero antes de entrar en la sintaxis conviene hacer una autopsia incómoda: la de casi todos los agentes multi-paso que hemos escrito hasta ahora.

«Y luego» no es una dependencia

Abre cualquier agente multi-paso tuyo y encontrarás una cola. Paso uno, paso dos, paso tres, cada uno esperando educadamente a que termine el anterior.

Ahora mira de cerca. La mitad de esas esperas no esperan nada. El paso tres no lee la salida del paso dos: está en fila porque ese fue el orden en el que lo escribiste.

Un grafo tiene exactamente dos piezas, y las dos caben en una frase. Un nodo es una unidad de trabajo: un encargo acotado, una entrada, una salida. Una arista es una dependencia de datos: lo que produce este nodo alimenta al siguiente. Nada más. Con esa definición en la mano, la pregunta que le haces a cada «y luego» de tu agente es de una simpleza brutal: ¿el paso siguiente lee lo que produjo el anterior? Si no lo lee, ahí no hay arista. Hay tiempo muerto.

Tu script lineal ya es un grafo, por cierto. Es el peor grafo disponible: una cadena sin ramas donde cada nodo tiene una entrada y una salida, donde todo el contexto vive en una sola cabeza y donde un fallo en el paso C deja huérfano para siempre lo que produjo A.

Por eso el primer ejercicio de la ingeniería de grafos no es añadir agentes. Es recortar flechas: recorrer la cadena, encontrar las dos o tres aristas que no transportan datos y cortarlas. La cadena colapsa de lado y aparece algo más ancho: un puñado de nodos independientes que pueden correr a la vez y desembocan en el único que de verdad los necesita a todos.

El guion que no piensa

Aquí es donde entra la herramienta. Un dynamic workflow es un script de JavaScript plano que Claude escribe para la tarea que le describes y que un runtime ejecuta en segundo plano, aislado de tu conversación. El script sostiene el plan —el bucle, las ramas, los resultados intermedios viven en variables del script— y al contexto de Claude solo vuelve la respuesta final.

La analogía que a mí me funciona es la médula espinal. Cuando retiras la mano de la sartén no interviene la corteza cerebral: el arco reflejo se resuelve abajo, sin pasar por el cerebro, porque pasar por el cerebro sería lento y caro. En un workflow ocurre lo mismo: el juicio vive en los nodos y el reflejo vive en las aristas. Cada nodo es un subagente con contexto limpio pensando su encargo; cada arista es código —un filter, un flat, un dedupe, un if—. Y el código no consume tokens. Coordinar dieciocho agentes cuesta cero pensamiento de modelo, porque un script no es una conversación.

Las primitivas que vas a usar el noventa por ciento del tiempo caben en una mano:

  • agent(prompt, opts) lanza un subagente con su propio contexto. Si le adjuntas un schema JSON, el resultado vuelve validado y estructurado. Si lo paras a mitad o se topa con un error irrecuperable de la API, resuelve a null en vez de tumbar el lote entero.
  • parallel([...]) ejecuta un conjunto de tareas a la vez y espera a todas. Es una barrera.
  • pipeline(items, etapa1, etapa2, …) hace pasar cada elemento por todas sus etapas de forma independiente, sin barrera entre ellas: el elemento A puede ir por la etapa 3 mientras el B sigue en la 1, y los rápidos terminan pronto en vez de hacer cola detrás del lento.
  • phase(título) agrupa lo que viene debajo bajo un epígrafe en la vista de progreso, log() escribe un mensaje por encima de las fases, y args es la entrada que le pasas a un workflow guardado.

Y hay un detalle que retrata la filosofía entera del diseño: dentro del script, Date.now(), Math.random() y un new Date() sin argumentos lanzan una excepción. No es una manía. Están prohibidos para que relanzar un run repita exactamente las mismas llamadas y pueda reutilizar los resultados ya completados. El guion es determinista por contrato: la criatura improvisa dentro del nodo, el mapa no improvisa nunca.

En la misma línea, el script no toca el disco ni ejecuta comandos, y un import() hace que el run falle antes de arrancar. Quien lee, escribe y ejecuta son los agentes. El script solo los coordina.

Contratos en los nodos, datos en las aristas

Un nodo sobre el que no puedes razonar es un nodo que no puedes paralelizar. La solución es un contrato: entrada explícita, salida con forma definida, un solo encargo. En la práctica el contrato es el schema: cuando obligas a un subagente a devolver JSON validado, conviertes su salida en algo que el siguiente nodo consume sin adivinar. Esa es toda la diferencia entre un nodo que se puede cablear en un grafo y un nodo que solo funciona cuando lo lee un humano.

La arista también tiene contrato. No es «B va después de A»: es una promesa sobre lo que cruza. A produce esta forma, B fue construido para consumir esta forma. Nombra tus aristas por sus datos y no por su orden, y pasan dos cosas buenas: sabes al instante si la arista es real, y puedes cambiar el nodo de cualquiera de los dos extremos sin tocar el resto mientras la forma se mantenga.

Guarda los agentes para el juicio. La fontanería es código, y el código sale gratis.

Este es uno de los ahorros silenciosos de pensar en grafos. Una cantidad sorprendente de lo que hoy quemamos en tokens es, en realidad, una arista: aplanar una lista, quitar duplicados, filtrar nulos, elegir rama con un switch sobre una salida ya validada. Un grafo donde cada arista es un agente es un grafo pagando alquiler por su propio cableado.

El diamante

Junta una apertura y un cierre y tienes la topología de casi todo grafo serio: el diamante. Un nodo parte el encargo, muchos nodos trabajan en paralelo, un nodo funde los resultados. Esa forma está detrás de una auditoría de seguridad, de un informe de investigación, de una migración de quinientos ficheros y de una revisión de código. Cambias las fuentes y los prompts y el esqueleto aguanta.

La forma canónica merece memorizarse: abre en paralelo para ganar amplitud, reduce con código para comprimirla, cierra con un agente que sintetice. Nueve fuentes investigadas a la vez y el contexto de Claude no sostiene las nueve en ningún momento: cada subagente carga con la suya y solo cruza el resultado.

De la cadena al diamanteDos formas de repartir exactamente el mismo trabajoCadenaPaso 1Paso 2Paso 3Paso 4Un solo contexto lo sostiene todoUn fallo a mitad deja huérfano lo anteriorCada paso espera al que va delanteLatencia = suma de todos los pasosDiamanteverificador en la aristareparte1 agentetrabajan en paralelocontexto propio por nodoreducecódigo: filtra, aplana, deduplicasintetiza1 agente escribe la respuestaContrato en el nodo: un schema JSONLas aristas son código: cero tokensUn nodo que revienta resuelve a nullMuros del runtime: hasta 16 agentes a la vez · 4.096 elementos por llamada a parallel() o pipeline() · 1.000 agentes por runFuente: documentación de Claude Code · code.claude.com/docs/en/workflows
De la cadena al diamante: la misma carga de trabajo, dos topologías.

La decisión fina está en el cierre. Una barrera —parallel()— obliga a todo a esperar al nodo más lento antes de que arranque la etapa siguiente, y solo se la gana cuando la etapa necesita de verdad el conjunto completo: un dedupe cruzado entre fuentes, una salida temprana si todo vino vacío, un prompt que compara cada hallazgo contra todos los demás. Para lo demás, pipeline(): cada elemento fluye a su ritmo. «Queda más limpio en el código» no es un motivo. La latencia de barrera es tiempo muerto real y medible.

Escépticos en la arista

En la entrega del bucle escribí que el que cocina no es el que prueba la sal: hacedor y verificador, separados. El grafo convierte esa idea en estructura, porque el verificador se muda a la arista. Antes de que un hallazgo cruce hacia el informe, un nodo cuyo único encargo es intentar tumbarlo le corta el paso. Si sobrevive, cruza. Si no, nunca llega a tu respuesta.

Tres variantes que merecen sitio en el cinturón:

  • Verificación adversarial. Por cada hallazgo, N escépticos independientes con la instrucción explícita de refutarlo. Solo pasa si sobrevive a la mayoría.
  • Verificación con lentes distintas. Cada verificador mira desde un ángulo —corrección, seguridad, reproducibilidad—, porque la diversidad caza modos de fallo que N copias idénticas no verán jamás.
  • Panel de jueces. N intentos desde ángulos distintos, jueces en paralelo puntuando y una síntesis que parte del ganador injertando lo mejor de los finalistas.

No es teoría: /deep-research, el workflow que viene de serie en Claude Code, es exactamente esto en producción. Parte tu pregunta en ángulos, busca en paralelo, cruza las fuentes, vota cada afirmación y filtra del informe final las que no sobrevivieron. Y cuando un verificador no puede comprobar algo —un límite de peticiones, un error de API— la afirmación se marca como no verificada en lugar de darse por refutada, que es la distinción honesta.

El fallo, mientras tanto, queda contenido en su nodo. El subagente que revienta dentro de un parallel() resuelve a null y los otros ocho vuelven con su trabajo; un .filter(Boolean) a la salida hace de dique. Diseña cada cierre para tolerar huecos en vez de asumir el conjunto completo.

Ciclos que se secan

Hay trabajos cuyo tamaño no conoces hasta estar dentro: un barrido de bugs donde encontrar uno destapa tres. Eso pide un ciclo, una arista controlada de vuelta a un nodo anterior. Y un ciclo es un bucle, así que aplican las leyes del bucle: si no puedes decir cuándo converge, no tienes un ciclo; tienes una factura.

El patrón que sí converge es agotar el pozo: sigue lanzando buscadores hasta que K rondas consecutivas no saquen nada nuevo, y para. Y el detalle que separa el ciclo que converge del que se desboca —el que casi todo el mundo falla la primera vez— es contra qué deduplicas. Deduplica contra todo lo visto, no solo contra lo confirmado. Si comparas cada ronda únicamente con los hallazgos que sobrevivieron a la verificación, los rechazados reaparecen ronda tras ronda, el pozo no se seca nunca y has construido una máquina que paga por redescubrir los mismos callejones sin salida para siempre.

Lo que cuesta y dónde están los muros

El grafo reparte el gasto de un modo que un agente monolítico no puede. Hay nodos acotados y repetitivos —extrae este campo, clasifica este ticket— y nodos donde vive el juicio de verdad —sintetiza el informe, adjudica el hallazgo—. Cada agent() puede fijar su propio modelo, así que los nodos aburridos bajan a uno barato y los tokens caros se quedan donde hay criterio que ejercer. Por defecto todo hereda el modelo de tu sesión, de modo que un run grande factura entero a esa tarifa salvo que el guion diga otra cosa: merece un vistazo a /model antes de soltar la flota.

Conviene también saber dónde están los muros del runtime:

LímiteValor
Agentes concurrentesHasta 16, menos si hay menos CPUs disponibles
Elementos por llamada a parallel() o pipeline()4.096, y una lista más larga se rechaza con un error
Agentes totales por run1.000
Aviso de run grandeMás de 25 agentes o más de 1,5 millones de tokens proyectados

Ese último es un aviso, no un freno: no pausa nada ni limita nada, solo te señala hacia /workflows, donde ves los tokens que lleva gastados cada agente y, por fase, cuántos agentes, cuántos tokens y cuánto tiempo va corrido, con teclas para pausar, reanudar o parar. Dos salvedades sobre ese aviso: si tú le has fijado una talla al workflow, el número de agentes de esa talla sustituye al umbral de 25; y con ultracode encendido no aparece, porque encender ultracode ya es decir que sí a los runs grandes.

Y si prefieres cortar por lo sano antes de empezar, /config te deja fijar una talla orientativa para los grafos que Claude diseñe: small apunta a menos de 5 agentes, medium —el valor por defecto— a menos de 15, large a menos de 50, y unrestricted deja que Claude dimensione a ojo. Es una recomendación que se le pasa al modelo, no un tope duro; los límites del runtime siguen aplicando por debajo.

Lo bueno de parar es que parar no duele demasiado. Al relanzar, los nodos completados devuelven su resultado guardado y solo se re-ejecuta lo que cambió o falló, aunque con una letra pequeña que conviene conocer: a partir del primer agente cuyo prompt cambió, todo lo que venía detrás se vuelve a ejecutar aunque hubiera terminado bien.

Cómo se enciende

Muy poca ceremonia. Tres puertas de entrada:

  1. Pídelo. Escribe la palabra clave ultracode en tu prompt —o simplemente «usa un workflow», con tus palabras— y Claude redacta el guion para esa tarea en lugar de trabajarla turno a turno.
  2. Ejecuta uno hecho. /deep-research viene de serie y no se autoinvoca: solo corre cuando lo llamas.
  3. Deja que decida. Con /effort ultracode, Claude planifica un workflow para cada tarea sustancial de la sesión. Más tokens y más tiempo por tarea: es la marcha larga.

Antes de arrancar, Claude Code te enseña las fases previstas y te pide permiso, con la opción de leer el guion en crudo o de retocar el prompt. Cuánto te pregunta depende de tu modo de permisos: en modo automático, solo la primera vez; en bypass permissions, con claude -p o desde el SDK, no pregunta nunca.

En cuanto a disponibilidad, están en todos los planes de pago, con acceso a la API de Anthropic y en Amazon Bedrock, Google Cloud Agent Platform y Microsoft Foundry. En Pro hay que encenderlos a mano desde la fila de Dynamic workflows de /config.

Un matiz que me parece elegante: la palabra clave solo es un opt-in si la has escrito tú. Un prompt que llega por -p, desde una tarea programada o desde el comentario de una pull request no dispara un workflow por mencionar ultracode (ojo si vas con una versión anterior a la 2.1.210 de Claude Code: antes de esa, sí lo disparaba desde cualquiera de esas rutas). Y si no quieres nada de esto, se apaga entero desde /config, desde settings.json o con una variable de entorno, para ti o para toda la organización.

Guardar el mapa

El cierre del ciclo de vida es la parte que más me gusta. Cuando un run sale bien, pulsas s en /workflows y el guion se guarda como comando: en .claude/workflows/ del proyecto, versionado con el repo y disponible para quien lo clone, o en tu directorio personal para tenerlo en todas partes. Acepta entrada vía args, se relanza por nombre y puede viajar dentro de un plugin para distribuirlo entre equipos.

Así, la orquestación que ayer fue una buena improvisación hoy es un artefacto con nombre, revisable en una pull request como cualquier otro código. Y si tienes que editarlo a mano, hay un detalle que rompe cosas en silencio: el bloque export const meta tiene que ser la primera sentencia del fichero y un objeto literal. Si metes ahí una variable o una llamada a función, el comando desaparece del autocompletado de / sin decirte por qué.

Juicio × topología

Todo lo anterior apunta al mismo sitio: el techo de tu agente casi nunca es el modelo, es la forma del trabajo que le entregaste. Una cadena obliga a un solo contexto a sostenerlo todo, a un solo fallo a detenerlo todo y a cada paso rápido a esperar detrás del más lento. Un grafo reparte el contexto entre una flota, contiene el fallo en su nodo y te regala estructura sobre la que envolver confianza: contratos en los nodos, escépticos en las aristas, rutas que se resuelven igual todas las veces.

En la primera entrega dejé una fórmula: tu palanca es habilidad × claridad. El grafo le añade un factor.

Tu palanca ya no es solo habilidad × claridad. Es juicio × topología: qué piensan los nodos y qué forma tiene lo que los une.

El bucle era el metabolismo de la criatura. El grafo es su anatomía. Y la vuelta de tuerca final es la misma que cerraba la primera entrega: ya no hace falta dibujar el grafo a mano. Describes el objetivo y Claude escribe el guion —descompone, abre, verifica, funde— a medida de ese run. Un grafo creando un grafo.

La criatura ya no hace cola. Reparte el trabajo, contiene sus fallos, verifica sus propios hallazgos y guarda el mapa para la próxima vez. Lo único que sigue sin poder hacer es decidir qué merece la pena construir. Esa arista, de momento, sigue llegando hasta ti.


Referencias

Pablo Formoso
autor

Pablo Formoso

Notas de campo desde la intersección de datos, IA, y filosofía aplicada.

entradas
64
desde
2024

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *