Mostrando entradas con la etiqueta Vibe Coding. Mostrar todas las entradas
Mostrando entradas con la etiqueta Vibe Coding. Mostrar todas las entradas

miércoles, noviembre 04, 2026

Cómo portar un proyecto de Azure a Cloudflare: Cómo lo hicimos con Weave.js de Inditex Tech Open Source

Cuando Inditex Tech Open Source, conocida por su cultura técnica, excelencia y comunidad sacó esta propuesta sabíamos que teníamos que colaborar y aportar nuestro granito de arena a la comunidad. Da gusto ver a una empresa española apostar por la tecnología, el talento y la innovación, y hacerlo con un propósito que va más allá de lo que construye: también comparte ese trabajo para que otros podamos aprender, experimentar y llevarlo un paso más allá.

Figura 1: Cómo portar un proyecto de Azure a Cloudflare.
Cómo lo hicimos con Weave.js de Inditex Tech Open Source

Esa forma de entender la tecnología encaja de lleno con el ADN de Cloudflare. Nosotros también creemos que compartir lo que aprendemos y contar abiertamente cómo construimos nuestra tecnología es parte del trabajo. De ahí nuestro blog de Cloudflare, donde entramos hasta la cocina de lo que hacemos, nuestra apuesta por la transparencia y un tier gratuito amplio y accesible para todos los desarrolladores del mundo.

Así que decidimos llevar esa afinidad al terreno que más nos gusta: construir. Y ahí apareció un reto a la altura, Weave.js, una herramienta para crear aplicaciones de colaboración en tiempo real, como pizarras colaborativas y editores de diagramas. Nuestra forma de contribuir sería explorar cómo llevarla a Cloudflare y compartir con la comunidad lo que aprendiéramos por el camino.


Al mirar todas las piezas el backend, el almacenamiento, la sincronización, la autenticación y la IA, nuestra primera pregunta técnica fue inevitable: 

«¿Cuánto tardaría en hacer funcionar todo esto en Workers?».

Nadie nos lo pidió. Lo hicimos porque nos picó el gusanillo y porque (seremos sinceros) en Cloudflare todos somos builders: nos gusta construir, probar ideas y hacer shipping, no dejarlas en una presentación. Y aquí teníamos un nuevo reto para poner todo eso en práctica. }:)

Lo interesante era comprobar cuánto podíamos simplificar el despliegue y la operación al tener todas las piezas en una misma plataforma: Workers para la lógica, D1 para los datos, Queues para las tareas en segundo plano y Access para la autenticación. Menos infraestructura que administrar y más tiempo para el producto. Y ahí entraban la «magia» de los Durable Objects para coordinar las salas en tiempo real, R2 para almacenar contenido sin cargos por transferencia de salida y Workers AI para integrar inferencia de baja latencia sin gestionar servidores de modelos.

Figura 3: El reto de migrar Weaver.js a Cloudflare

No se trataba solo de hacerlo funcionar, sino de explorar lo que permite hoy la plataforma: reducir complejidad, ajustar buena parte del coste al uso real y llevar las ideas antes a producción. Todo con una aplicación de verdad, no un «hola, mundo», y descubriendo por el camino qué encajaba, qué había que adaptar y dónde estaban los límites. Lo que os voy a contar hoy es esa aventura. Y os adelanto que fue más divertida ¡y accidentada! de lo que esperaba.

El punto de partida: el repo de Inditex tal cual

Lo primero que hice fue clonar los dos repositorios públicos (weavejs-backend y weavejs-frontend) y leer el código de arriba a abajo. La arquitectura original de Weave.js era la que podríais imaginar para una aplicación Node.js moderna y bien hecha:

Figura 4: Diagrama de arquitectura de Weave.js
  • Backend: Express.js corriendo en un servidor Node.
  • Almacenamiento: Azure Blob Storage para guardar el estado de las salas (documentos Yjs en binario) y los assets (imágenes, vídeos).
  • Base de datos: PostgreSQL para todo lo demás como salas, páginas, hilos de comentarios, chats o tareas de exportación.
  • Cola de trabajos: pg-boss, una librería que usa PostgreSQL como backend de colas para gestionar los trabajos asíncronos (generación de imágenes con IA, exportaciones a PDF, etc.).
  • Tiempo real: Azure Web PubSub para sincronizar el documento Yjs entre todos los clientes conectados a una sala y para el canal de eventos secundario (lo que llamábamos el "comm-bus").
  • Autenticación: better-auth con su propia tabla en PostgreSQL.
  • IA: Google Generative AI para la generación de imágenes.
  • Frontend: TanStack Start + Vite + Nitro, desplegado también en un servidor Node.
No está nada mal para una aplicación colaborativa en tiempo real. La gente de Inditex Tech lo tiene muy bien hecho. Pero desde mi perspectiva había una pregunta obvia: 

¿Podemos hacer todo esto con Cloudflare y sin tocar apenas el código del frontend?


El proyecto del Porting a Cloudflare

Como es un proyecto complejo, decidimos hacerlo por partes, así que antes de entrar en detalle de cada una de las partes, os dejo el resumen de lo que cambiamos. Cuáles fueron los cambiso que realizamos pieza por pieza para que Weave.js siguiera funcionando perfectamente, pero en Cloudflare.

Figura 5: El mapa del cambio

Y ahora, vamos con cada una de las partes, que hay mucho que contar de todas y cada una de ellas, como vais a poder leer aquí.

De Express a Hono: el cambio más fácil

Este fue el cambio más agradable de todos. Hono es un framework HTTP tan parecido a Express que la migración de rutas fue casi mecánica. La diferencia importante es el modelo de ejecución. Express espera vivir en un proceso Node.js persistente. Hono está diseñado para correr en un Worker de Cloudflare, es decir, sin estado global entre peticiones, con acceso a los bindings de la plataforma (env.DB, env.IMAGES_BUCKET, etcétera) directamente desde el contexto de Hono.
// Antes: Express
app.get('/rooms/:roomId/images', requireAuth, async (req, res) => {
  const images = await db.query('SELECT ...');
  res.json(images);
});

// Después: Hono en Workers
imagesRouter.get('/rooms/:roomId/images', requireAuth, async (c) => {
  const result = await c.env.DB.prepare('SELECT ...').all();
  return c.json(result.results);
});
El router de Hono se monta en el Worker, y el Worker exporta los handlers de fetch y queue. Nada más.

De Azure Blob Storage a R2: sin egress, sin dramas

Azure Blob Storage y R2 son conceptualmente idénticos: almacenamiento de objetos con clave. La migración fue directa. Lo que antes era esto:
await blobClient.uploadData(buffer, { 
    blobHTTPHeaders: { blobContentType: contentType } });
Pasó a ser esto:
await c.env.IMAGES_BUCKET.put(key, buffer, { httpMetadata: { contentType } });
Creamos cuatro buckets en R2:
  • weavejs-rooms: estado binario de los documentos Yjs
  • weavejs-images: imágenes subidas por los usuarios
  • weavejs-videos: vídeos
  • weavejs-generated-images: imágenes generadas por IA
La gran ventaja: R2 no cobra egress. En Azure, cada vez que un cliente descarga una imagen, pagas. En R2, no. Para una aplicación colaborativa donde se sirven imágenes constantemente, eso no es un detalle menor.

De PostgreSQL a D1 + Durable Objects: aquí sí que hay que pensar

Este fue el cambio más interesante. Y el que más hay que entender bien. D1 es un SQLite gestionado por Cloudflare. Perfecto para datos relacionales que no necesitan fuerte consistencia distribuida en tiempo real: salas, páginas, hilos de comentarios, metadatos de imágenes. Definimos las migraciones en SQL y listo.
CREATE TABLE rooms (
  id TEXT PRIMARY KEY,
  name TEXT NOT NULL,
  kind TEXT NOT NULL DEFAULT 'showcase',
  status TEXT NOT NULL DEFAULT 'active',
  created_at TEXT NOT NULL,
  updated_at TEXT NOT NULL
);
Pero hay un tipo de dato que D1 no puede manejar bien: el estado de conexión en tiempo real. ¿Qué clientes están conectados ahora mismo a qué sala? Eso requiere consistencia fuerte, una sola fuente de verdad. Para eso usamos un Durable Object.

El ConnectionRegistry es un DO singleton que usa SQLite interno (la API ctx.storage.sql de los DOs de nueva generación) para rastrear las conexiones activas. Una sola instancia, en un solo lugar del planeta, con garantía de consistencia fuerte. Exactamente lo que necesitas para algo así.

De Azure Web PubSub a Durable Objects: el cambio más grande

Azure Web PubSub era el corazón de la sincronización en tiempo real. Cada sala tenía un "hub" donde se publicaban y suscribían los eventos del documento Yjs. Reemplazarlo fue el reto más técnico de toda la migración. 

La solución: dos Durable Objects por sala.

1.- RoomSync: el documento Yjs vivo

RoomSync es el DO que mantiene el documento Yjs de cada sala. Implementa el protocolo y-websocket directamente, de forma que el cliente no sabe que está hablando con un Worker en lugar de con el servidor Node original.

Cuando un cliente se conecta, el Worker negocia la URL del WebSocket y el cliente conecta directamente al DO. El DO usa la Hibernation API de Cloudflare, lo que significa que cuando no hay mensajes, el DO hiberna y no consume CPU. Los WebSockets se mantienen abiertos sin coste.

El estado del documento Yjs se persiste en R2 cada vez que hay cambios, para que sobreviva reinicios del DO.
async webSocketMessage(ws: WebSocket, message: string | ArrayBuffer) {
  // Protocolo y-websocket: sync, update, awareness...
  const data = typeof message === 'string'
    ? new TextEncoder().encode(message)
    : new Uint8Array(message as ArrayBuffer);
  // broadcast a todos los clientes conectados
  for (const client of this.ctx.getWebSockets()) {
    if (client !== ws && client.readyState === WebSocket.READY_STATE_OPEN) {
      client.send(data);
    }
  }
}

2.- CommBus: el canal de eventos secundario

Además del documento Yjs, la aplicación tiene un segundo canal de WebSocket para eventos más ligeros: notificaciones de que una imagen se ha procesado, progress de exportaciones, heartbeats. A esto lo llamábamos el "comm-bus".

CommBus es otro DO por sala, más simple que RoomSync. Solo hace broadcast de mensajes JSON a todos los clientes conectados. También usa Hibernation API.

Lo más interesante: con Azure Web PubSub, el backend publicaba eventos en el hub y Azure se encargaba del fanout. Con los DOs, el Worker llama directamente al DO de la sala y el DO hace el fanout. Sin intermediarios, sin latencia adicional de round-trip a Azure.

De pg-boss a Cloudflare Queues: colas sin PostgreSQL

En el caso de pg-boss éste usaba PostgreSQL como backend de cola. Los trabajos asíncronos (generación de imágenes con IA, transformaciones de imágenes, exportaciones a PDF) se encolaban en una tabla de PostgreSQL y un worker de Node los procesaba.

En nuestros Workers, esto se convierte en Cloudflare Queues. El producer es el Worker del backend: cuando llega una petición de exportación o generación de imagen, encola el mensaje y devuelve un 202 Accepted con un taskId.

await c.env.WORKLOADS_QUEUE.send({ jobType: 'generate-images', taskId, roomId, payload: body, }); return c.json({ taskId, status: 'pending' }, 202);

El consumer es el mismo Worker, pero en su handler de queue:
 
async queue(batch: MessageBatch%lt;WorkloadMessage%gt;, env: Env) {
  for (const message of batch.messages) {
    await handleWorkload(message.body, env);
    message.ack();
  }
}

El estado de cada tarea se guarda en D1 (tabla tasks), y el frontend hace polling hasta que el estado cambia a completed.

De better-auth a Cloudflare Access: autenticación sin base de datos

Vamos con better-auth que también estaba en PostgreSQL e implicaba gestionar sesiones, tokens de refresco, tablas de usuarios... Todo eso desapareció:

Pusimos Cloudflare Access delante de la aplicación.

Access gestiona el login (con el proveedor de identidad que quieras: Google, GitHub, OTP, passkeys) y emite un JWT firmado que llega a cada petición como la cookie CF_Authorization o el header Cf-Access-Jwt-Assertion. El backend solo tiene que verificar ese JWT:

const { payload } = await jwtVerify(token, JWKS, {
  issuer: env.CF_ACCESS_TEAM_DOMAIN,
  audience: env.CF_ACCESS_AUD,
});
c.set('userId', payload.sub ?? payload.email);

Sin tabla de usuarios. Sin tabla de sesiones. Sin refresh tokens. El JWKS se rota automáticamente cada seis semanas y jose lo gestiona con createRemoteJWKSet, que cachea y rota transparentemente. No está mal para eliminar toda una capa de complejidad.

De Google Generative AI a Workers AI: IA en el edge

La generación de imágenes con IA pasó de llamar a Google Generative AI desde un servidor Node a usar el binding AI de Workers, con los modelos FLUX disponibles en Workers AI, enrutado todo a través de AI Gateway.
const result = await env.AI.run(
  '@cf/black-forest-labs/flux-1-schnell',
  { prompt, steps: 8 },
  { gateway: { id: env.AI_GATEWAY_ID, skipCache: false } }
);

AI Gateway añade logging, caché semántica y control de costes sin cambiar una línea del código de inferencia. Si el mismo prompt ya se generó antes, devuelve la imagen cacheada en milisegundos.


Para los modelos que no están en Workers AI (como gpt-image-1 de OpenAI) seguimos usando la API directa, pero también enrutada a través de AI Gateway para tener el mismo sistema de observabilidad.



El chat con IA también pasó a Workers AI, usando el modelo llama-3.3-70b-instruct-fp8-fast con streaming. El Worker devuelve el ReadableStream de SSE directamente desde el binding, sin transformaciones intermedias.

De Node.js con sharp a Cloudflare Images: transformaciones sin binarios nativos

Aquí nos encontramos con la limitación más dura del modelo de Workers: no puedes ejecutar binarios nativos. sharp, skia-canvas, ffmpeg son todos binarios de Node.js que no pueden correr en un isolate de V8. Para las transformaciones de imagen básicas (flip, escala de grises, eliminar fondo) usamos el Cloudflare Images binding, que hace las transformaciones de forma nativa en el edge:
  
const result = await env.IMAGES
  .input({ imageKey: `${roomId}/${imageId}` })
  .transform({ flip: 'h' })
  .output({ format: 'image/webp' });

Para las operaciones más complejas que no soporta el binding, como la inversión de colores, el Worker devuelve una señal al frontend indicando que debe procesar la imagen client-side usando la Canvas API. No es perfecto, pero funciona. Podríamos haber implementado esta funcionalidad con Cloudflare Containers, pero dejamos esto para el roadmap futuro.

Las exportaciones a PDF y las capturas de página para la presentación son el único caso pendiente. Esas tareas se encolan y quedan marcadas como requires-external-processing. La solución pendiente es desplegar un Cloudflare Container que ejecute el código Node.js original de exportación y escriba el resultado de vuelta a R2.

El frontend: TanStack Start en Workers con Nitro

El frontend ya usaba TanStack Start + Vite + Nitro. Nitro tiene un preset cloudflare_module que compila el servidor SSR directamente a un módulo de Worker. Un único cambio de configuración:
NITRO_PRESET=cloudflare_module vite build --mode production
Y el resultado es un index.mjs listo para wrangler deploy, con los assets estáticos en .output/public/ servidos desde Workers Static Assets. Los únicos cambios que tuvimos que hacer en el frontend:
  • Eliminar sharp (no puede importarse en un Worker): añadimos un stub que lanza un error descriptivo.
  • Reescribir el middleware de "coming soon" para usar la Web Crypto API (crypto.subtle) en lugar de crypto.createHmac de Node.
  • Reemplazar useGetAzureWebPubSubProvider por useGetWebsocketsProvider, que usa WeaveStoreWebsockets en lugar del cliente de Azure.
Ese último cambio fue casi poético en su simplicidad: una sola línea diferente en el componente de la sala.

Los bugs que encontramos por el camino

La migración no fue perfecta desde el primer momento. Os cuento los más divertidos.
  • El race condition del WeaveProvider. El SDK de Weave llama a registerStore() dentro de un método start() asíncrono. Si React desmontaba el componente <WeaveProvider> antes de que start() terminara —lo que pasaba cuando cambiaba el key del componente al resolverse la primera página— destroy() se llamaba antes de que this.store estuviera asignado. 
Resultado: TypeError: Cannot read properties of undefined (reading 'disconnect'). La solución: no montar <WeaveProvider> hasta que actualPageId esté definido, para que la key sea estable desde el primer render.
  • La identidad del usuario. Las salas que había creado con el sistema original de better-auth usaban un UUID v4 generado por la propia aplicación. Cloudflare Access usa el sub del JWT, que es el UUID de la identidad en Access: otro valor completamente distinto. Así que al arrancar con Access, el backend no encontraba mis salas en D1 porque los IDs no coincidían.
La solución fue buscar el sub de mi usuario de Access mediante la API de Cloudflare y lanzar una query de migración directamente en D1 para reasignar los room_users al nuevo userId. Desde fuera me imagino que esto suena a obviedad, pero cuando estás depurando a las 11 de la noche y las salas "desaparecen"... no es tan obvio. }:)
  • Las rutas del frontend apuntando a endpoints inexistentes. Al auditar todos los endpoints descubrimos que varios frontends llamaban a rutas que en el nuevo backend no existían: /rooms/:roomId/chats en lugar de /rooms/:roomId/ai/chats, el endpoint de presentación en /api/v1 en lugar de /api/v2, las rutas de templates con scope de sala que el backend global no tenía... Una auditoría completa de todos los apiFetch del frontend contra todos los routers del backend reveló diez discrepancias. Las corregimos todas.
El resultado final

La arquitectura final tiene exactamente dos Workers desplegados:
  • Backend: Hono + D1 + R2 (×4) + Durable Objects (×3 clases) + Queues + Workers AI + Cloudflare Images + Cloudflare Access.
  • Frontend: TanStack Start + Nitro + Workers Static Assets.
Sin servidores que escalar. Sin bases de datos que parchear. Sin factura de Azure Web PubSub por conexiones WebSocket. Sin egress de Azure Blob Storage.

Figura 8: Arquitectura de Weave.js en Cloudflare

Y todo desplegable con dos comandos:
  • cd backend && npm run deploy
  • cd frontend && npm run deploy
¿Mereció la pena? Para mí, rotundamente sí. Y no solo como ejercicio técnico. La respuesta a mi pregunta inicial "¿cuánto tarda en correr esto en Workers?" resultó ser "un par de días quemando tokens". Para una aplicación colaborativa en tiempo real con sincronización CRDT, IA generativa, colas de trabajos asíncronos y autenticación Zero Trust.

Lo más valioso que me llevé no es el código. Es la comprensión de cómo los Durable Objects resuelven el problema de estado distribuido en tiempo real de una forma que ningún servicio gestionado externo puede igualar: el estado vive en el edge, co-localizado con los clientes, sin round-trips a una región central.

Eso, para una aplicación de colaboración en tiempo real, es EL detalle.

Y dicho esto: si alguien de Inditex Tech Open Source está leyendo esto y quiere charlar sobre la migración, ya sabéis dónde encontrarme, que seguro que podemos hacer más proyectos de estos juntos.

Saludos,

miércoles, septiembre 23, 2026

IA aplicada al ciclo completo del desarrollo de software

En muchas entrevistas o charlas con amigos surge la pregunta de "¿cómo te mantienes al día de la tecnología?" La respuesta desde hace años es muy similar. Se trata de estudiar todos los días, y yo lo hago leyendo todos los días mis blogs, asistiendo a eventos, disfrutando de lecturas de libros, viendo conferencias online, escuchando podcasts. Algo que para mía es "lo normal". Por eso siempre estoy metido en actividades. Es decir, hago conscientemente cosas para formarme todos los días.
Esta actividad es una formación Gratuita y Online de 1 hora de duración  que que tendrá lugar el día 29 de Septiembre a las 17:00 y donde se hablará no solo de VibeCoding, Spec Coding, Graph Engineering, Code Agents o Software Factories, sino también de Workflows, Skills, MCP, Arquitecturas RAG, Loop, Harnesses y, como no, QA y Seguridad, temas que debes conocer hoy en día si quieres dedicarte al mundo de la tecnología.


Es una oportunidad cómoda de estar una hora en mi jornada asistiendo a un evento en remoto, escuchando a profesionales y, lo mismo, lo hago desde mi terminal móvil paseando por la ciudad, o sentado en un banco del parque de la "Tapada das Necessidades" en Lisboa, donde aprovecho para ir a leer un poco las tardes de buen tiempo. 

En la formación estarán Santos Pardos Gotor, que es Arquitecto de soluciones Cloud e instructor de AWS autorizado dando una ponencia de y luego habrá una mesa redonda a la que se unirán Ángel Gálvez Caballero, que es el CISO Avolta, e Iván Sanz Prieto, que es Senior Manager of Software Development for AI, Data & DevSecOps en Lumen Technologies. Así que seguro que puedo seguir aprendiendo cosas de sus experiencias.

Regístrate al Foro de IA aplicada al desarrollo de Software

Para poder venir tú también, lo único que tienes que hacer es inscribirte en el formulario como asistente, para venir el próximo día 29 de Septiembre por la tarde (a las 17:00 horas de España), como te he dicho totalmente gratuito y online, y te permitirá aprender cómo es el mundo de la creación de tecnología  hoy en día, para entender mejor donde estamos en creación de software, servicios digitales y productos informáticos.

Si quieres estar al día, y conocer de primera mano cómo son las amenazas, cuál es el estado de la ciberseguridad y, sobre todo, cómo protegerte tú, los tuyos y tu empresas, entonces solo necesitas rellenar el formulario y venir al evento con nosotros.

Al final, esta es una oportunidad para conectarse desde casa o el trabajo, y en poco más de una hora ponerse al día con uno de los temas que más preocupan hoy profesionalmente, como es la Inteligencia Artificial y el Desarrollo de Software. No desaproveches la oportunidad. Registra tu plaza aquí.

¡Saludos Malignos!

Autor: Chema Alonso (Contactar con Chema Alonso)  


domingo, septiembre 20, 2026

Vibe-Exploiting Discourse para hackear OpenAI con Claude Opus

Esta semana ha salido el Write-Up de cómo un grupo de investigadores consiguieron un Bug Bounty de OpenAI de 6.000 USD haciendo Vibe-Exploiting con Claude Opus. La explicación es lo que tenemos hoy en día en este mundo, donde se utiliza la Inteligencia Artificial para hacer el trabajo, lejos de lo que eran los sesudos Write-Ups de antes donde se explicaba con detalle la creación de los exploits, y, en este caso, evitar la protección de memoria de ASLR. Hoy en día es distinto.

El artículo lo podéis leer en Hacktron AI, y explica el proceso que al final ha seguido esta explotación, que tuvo lugar durante el mes de Julio - sin acceso a Mythos o Fable en aquel entonces -. Como podéis ver en el gráfico, el culpable es una librería de tratamiento de imágenes con un bug de Heap Overflow que permite lograr ejecución de código.
Esa librería contenía un CVE conocido, pero no parcheado correctamente en el software de ImageMagick que iba en la versión de Debian donde corría el software de Discourse que daba servicio al Forum de OpenAI. Como veréis, es todo un proceso de Bug Hunting con IA.

Figura 3:"Bug Hunter" escrito por David Padilla en 0xWord

A partir de ese momento, el SSO de OpenAI permitía crear/acceder a las cuentas tanto de terceros como de invitados, así que se podía robar una cuenta de un empleado de OpenAI y con ella acceder a las herramientas que utiliza como ChatGPT o CODEX y a todos los repositorios conectados a ellas. 
El proceso comienza usando Claude Opus 4.8 para que busque una imagen Docker de Discourse e investigue la librería en cuestión libheif. Y el modelo encuentra que no está parcheada. Así que se le pide que haga un exploit sobre ese bug conocido.
Con Claude Opus 4.8 se consigue hacer el exploit, pero sin saltarse ASLR. Con ASLR (Address Space Layout Randomization) activo, el modelo no es capaz. Pero.... llega Claude Opus 5 y la cosa cambia para bien para ellos, que consiguen que le haga el exploit con ASLR.
Como podéis ver, usando Claude Opus 5 son capaces de hacer el exploit para saltarse ASLR, y con Claude en modo autónomo con un loop para lograr el objetivo, son capaces de conseguir el RCE (Remote Code Execution) en el Docker de Discourse. 
Una vez conseguido esto, teniendo en cuenta que OpenAI tenía integrado este software con las cuentas de los usuarios de la empresa, consiguieron robar identidades de empleados, con ellas, el acceso a sus herramientas, y desde ellas a los repositorios conectados con sus cuentas, como GitHub o Gmail.
Al igual que vimos en el artículo de "Cómo crear un exploit 1-day sobre un CVE de Chrome con Vibe Coding usando Claude Opus (no Mythos) y poner en jaque todas las apps en Electron", el costo de este exploit no es tan alto - algo menos de 3.000 USD - pero sí que es un cambio radical en la forma en la que hemos buscado bugs siempre. Ahora le pedimos a la IA que los busque, y nosotros sólo le vamos guiando.
Por un lado, no me deja de maravillar como el desarrollo de Inteligencia Artificial ha cambiado radicalmente esta industria, y la búsqueda de bugs se ha convertido en algo más cercano a configurar el modelo correctamente que ha descubrir el bug en sí mismo.
Y eso es lo otro que me llama la atención, cómo este trabajo que tenía tanto de artesano, cada vez se ha automatizado más, y leer un write-up ya no es aprender profundamente sobre una arquitectura vulnerable, y entender los detalles del exploit. Ya son del tipo "configuramos Claude Opus 5 para que buscara cómo entrar y al tiempo estaba el RCE". Tal vez soy mayor, pero pierde cierta magia esto, aunque entiendo que es lo que hay que hacer.

¡Saludos Malignos!

Autor: Chema Alonso (Contactar con Chema Alonso)  


viernes, julio 24, 2026

AI Engineering Bootcamp: Basta de hacer tutoriales y construye tu propio asistente con IA en producción

Vivimos rodeados de Inteligencia Artificial, pero la inmensa mayoría de la gente que trabaja "con IA" en realidad se limita a llamar a una API, copiar un prompt de Twitter/X o encadenar un par de bloques en una herramienta no-code. Saben usar la IA como usuario avanzado, pero no entienden qué pasa por debajo: cómo se sirve un modelo, cómo se diseña un agente que razona y actúa, cómo se protege un sistema LLM de un ataque de prompt injection o cómo se lleva todo eso a producción para que funcione 24/7 sin que se caiga a la primera de cambio.


Esa distancia entre "usar IA" y "construir con IA" es, ahora mismo, la que separa a un consumidor de prompts de un auténtico AI Engineer. Y es precisamente esa distancia la que Ferrumox Academy ha diseñado para recorrer en 9 semanas con su AI Engineering Bootcamp.


Cohorte 2: arranca la semana del 2 de septiembre

El AI Engineering Bootcamp de Ferrumox Academy no es un curso de vídeos a tu ritmo ni una colección de slides sobre "el futuro de la IA". Es un programa intensivo y práctico: una sesión en directo por semana de 2 horas (tú eliges grupo de lunes, miércoles o viernes, de 18:00 a 20:00) y el resto de la semana para construir, con material previo antes de cada directo y un entregable funcionando al final de cada semana.


El objetivo final no es "terminar un curso". Es salir con tu propio asistente con IA corriendo en producción: accesible desde Telegram, con memoria persistente, capaz de orquestar varios agentes especializados vía MCP y conectado a tus propios documentos mediante RAG híbrido. Construido por ti, entendido por ti, no copiado de un repositorio de GitHub.

Un programa que va desde la inferencia hasta producción, semana a semana

A lo largo de las 9 semanas (con una sesión 0 bonus de preparación incluida) el temario progresa capacidad a capacidad, sin frameworks mágicos que oculten lo que está pasando por debajo:
  • Semanas 1-2: Infraestructura de inferencia propia, local y en la nube (Ollama, vLLM, APIs de OpenAI y Anthropic), y adaptación de modelos con LoRA y QLoRA.
  • Semanas 3-4: Context engineering, gestión de memoria persistente y diseño del bucle de agente (agentic loop) con el patrón ReAct y tool calling, implementado sin frameworks para entender de verdad el ciclo razonar-actuar-observar.
Figura 4: Semanas 00 a 03
  • Semanas 5-6: RAG avanzado con recuperación híbrida y reranking, y sistemas multi-agente con orquestación vía MCP siguiendo el patrón supervisor.
Figura 5: Semanas 04 - 07
  • Semanas 7-8: Seguridad de sistemas LLM, modelado de amenazas, prompt injection, jailbreaking y diseño de guardrails, y despliegue en producción con observabilidad, evals y control de costes.
  • Semana 9: Demo day, presentación del proyecto ante toda la cohorte y hoja de ruta para seguir construyendo.
Figura 6: Semanas 8 y 9

Uno de los puntos diferenciales del programa es precisamente el módulo de LLM Security: menos del 1% de los AI Engineers sabe auditar un sistema LLM de verdad, y este bootcamp dedica una semana completa a aprender a atacarlo y a defenderlo, algo que a día de hoy no se encuentra en ningún otro bootcamp en España.

Quién está detrás del programa

El bootcamp lo imparto directamente yo, Manuel S. Lemos, fundador de Ferrumox y Claude Certified Architect de Anthropic (la primera certificación técnica oficial que ha emitido la compañía, sólo accesible por invitación), además de AI Engineer en NaizFit, coautor del libro Hacking IA (0xWord, 2026), contribuidor de OWASP GenAI Security y Vicepresidente de ANBAN. Anteriormente Director Académico de IA & Big Data en GeeksHubs Academy durante cuatro años. También he dado charlas en el GenAI Summit EU, Codemotion Madrid, TofuConf, el Máster de Ciberseguridad del CIPFP Cheste y el podcast de Hackers, entre otros escenarios. 

Lo que se enseña en el bootcamp es, literalmente, lo que se construye en producción cada día. Ferrumox es el proyecto para unir dos cosas que normalmente van por separado: ingeniería de IA de verdad y formación de alto nivel. Por un lado está Fox, el motor de inferencia LLM en Rust, de código abierto y gratuito para siempre (sin planes de pago ni capital de por medio), pensado como sustituto directo de Ollama con hasta 4 veces más eficiencia gracias al prefix caching y al continuous batching.

Precio, plazas y un regalo que no falta en ninguna edición

La Cohorte 2 arranca la semana del 2 de septiembre de 2026 y tiene 36 plazas repartidas en 3 grupos de 12 (lunes, miércoles y viernes). Las primeras 12 plazas entran a 997 €; a partir de ahí el precio pasa a 1.200 €. Todas las sesiones se graban y quedan disponibles antes de 24 horas, así que si algún día no puedes conectarte en directo no te quedas fuera. 

Y, como no podía ser de otra manera en este blog, hay premio para los alumnos: cada persona de la Cohorte 2 recibe un ejemplar del libro Hacking IA: Jailbreak, Prompt Injection, Hallucinations & Unalignment de 0xWord, incluido sin coste extra en la plaza, y habrá un chat en MyPublicInbox constante conmigo y con Chema Alonso.

Go for it!

Si necesitas un empujón más para decidirte, el 10 de Agosto haremos una clase gratuita que te puedes apuntar desde nuestra web. Además el bootcamp incluye feedback escrito de tus proyectos en 48 horas, repo privado con todo el código, comunidad privada de la cohorte, acceso a las grabaciones de futuras ediciones y más sorpresas.

¡Happy hacking!

Autor: Manuel S. Lemos, Fundador de Ferrumox y director del AI Engineering Bootcamp

domingo, mayo 31, 2026

Cómo crear con Víbe Coding código ASM para AMSTRAD CPC 6128. Por si te animas a "sufrir" conmigo el Retro Vibe-Coding.

No, no se me había olvidado postear, ni iba a dejar de lado al "demonio cabrón", solo es que me ha tomado mucho más tiempo de lo que pensaba. Estos días atrás se me ocurrió la idea de hacerme con Vibe-Coding, o mejor dicho, con SPEC-Coding, una serie de utilidades y herramientas a bajo nivel para el AMSTRAD CPC 6128. Quería hacerlas en lenguaje ensamblador para tener más posibilidades de controlar el equipo, y al mismo tiempo más velocidad de ejecución que los programas interpretados por BASIC.

Figura 1: Cómo crear con Víbe Coding código ASM para AMSTRAD CPC 6128.
Por si te animas a "sufrir" conmigo el Retro Vibe-Coding.

Como idea inicial parecía muy sencilla, pero no ha sido así. Ya os dije que cuando estuve probando a hacerme el juego de Light-Cycles de Tron tuve que pelear bastante. Me dio bastantes errores y costó sacarlo adelante, pero después de varias horas, el programa salió. Eso sí, con un poco más de coste que saldría con los lenguajes más comunes como Python, o Rust, o Javascript. 

En este caso, viendo el tamaño del MS-DOS de 1981 del que os hablé hace poco, quería trabajarlo en ASM, y comenzar con hacer un Diskcopy a bajo nivel, que era una herramienta que todos los amantes del AMSTRAD CPC6128 teníamos siempre a mano. La idea es sencilla, se trataba de construir un analizador de disquetes, y un duplicador que no falle incluso si un sector está defectuoso, añadiendo re-intentos, copiado a bajo nivel, y además incluso, con IA, generar reparaciones de sectores.  Pero primero, con poder duplicar un disquete me daba por satisfecho.

Creando un proceso para hacer Vibe-Coding/Spec-Coding en ASM Z80 para AMSTRAD CPC

Pues no ha sido fácil. Un autentico dolor. Tanto que, después de más de treinta intentos he tenido todos los problemas de especificaciones que pudierais imaginar. Conseguir que se quedará centrado en ASM para el Z80 de AMSTRAD CPC no ha sido fácil, en cada dos o tres iteraciones añadía funciones en ensamblador de otros microprocesadores.  Tampoco ha sido fácil que cuando escribía el código se ciñera al AMSTRAD, y de repente los cargadores los llevaba al BASIC de Sinclair e incluso de Spectrum, haciendo que la compilación fuera un dolor. 
He estado tentado de leerme los fantásticos tutoriales de Chubiakumas que son una pasada y hacérmelo yo a mano como antaño. Al final, después de varias horas probando una y otra cosa, he conseguido que me funcione bien el proceso, aunque el código aún lo tengo al 1% de lo que quiero construir. Pero si te animas a probarlo tú, y quieres sufrir un rato conmigo, te lo dejo por aquí.

1.- El Prompt para pedir el código

No he utilizado ningún sistema de Spec-Coding todavía, así que sólo conseguir un programa Stand-Alone usando Gemini 3.5 Thinking y DeepSeek v3 DeepThink me ha dado bastantes problemas. Al final, he utilizado un Prompt que acote bien que el código se genere para ese entorno concreto.

Eres un experto programador en Z80 para el ordenador Amstrad CPC6128.
Necesito que generes código ensamblador (Z80) que cumpla estrictamente con las siguientes reglas:

1. **Solo instrucciones estándar Z80** (no usar códigos de operación no documentados ni instrucciones de terceros).
2. **El código debe ejecutarse sin fallos en un Amstrad CPC6128 real** (o emulador fiable como WinAPE, JavaCPC, Caprice).
3. **El programa debe arrancar en ORG &4000**
4. **No debe asumir nada sobre el estado previo del sistema** (inicializar todo lo necesario: modo de pantalla, colores, interrupciones, etc.).
5. **Uso del firmware** – se permite, pero solo llamadas bien documentadas (por ejemplo SCR_SET_MODE &BC0E, TXT_OUTPUT &BB5A, etc.). Si se usa acceso directo a hardware (VRAM, puertos), debe ser correcto para el CPC.
6. **Gestión de errores** – el programa no debe colgar el sistema. Si termina, debe retornar limpiamente (RET) o quedar en un bucle seguro.
7. **Comentarios claros** – cada sección debe explicar qué hace en relación al hardware del CPC (pantalla, memoria de vídeo en &C000, etc.).
8. **Ejemplos de código** – si se pide una tarea concreta (por ejemplo, mostrar texto centrado, dibujar gráficos, leer teclado), el código debe ser autocontenido y funcionar al cargarlo con LOAD y ejecutarlo con CALL &4000.

Antes de escribir el código, comprueba mentalmente:
- Las direcciones de firmware son correctas para el CPC6128.
- La memoria de vídeo en modo 1 es de 16000 bytes, desde &C000 hasta &amd;FE7F.
- El tamaño de la pila es suficiente.
- No se desborda la VRAM (escribir más allá de &FE7F corrompe el sistema).

[TAREA A REALIZAR]

No es un Prompt "perfecto", pero es el que mejores resultados me ha dado en todo el proceso para conseguir que no se me fuera a otros equipos, a otros lenguajes o a otros ensambladores.

2.- Compilación con pasmo

Hay otras alternativas, pero una vez tenía el código ASM generado por Gemini o por DeepSeek, lo he compilado con pasmo en formato BIN usando la cabecera AMSDOS, tal y como podéis ver en la siguiente captura. Nada complicada esta parte.
Pasmo lo puedes descargar desde la web del proyecto. Yo me he descargado la última versión, la he instalado y ha funcionado a la perfección en mi MacOS última versión, así que no debería darte ningún problema en ningún sitio.
De este proceso te deberá salir el código .BIN de tu programa, que es lo que deberemos llevar al disquete en la fase siguiente.

3.- Creación del disquete

Esta es una fase sencilla, ya que puedes hacer la creación de un disco virtual, usando Amstrad DSK Filesystem Manager. Para ello, crea primero un disquete con "New Disk Image" y luego el código .BIN que tienes que tener comprimido como FICHERO.BIN.ZIP lo arrastras a la parte de arriba a la derecha donde pone "Import to DSK".

Cuando tengas el fichero en la lista de archivos de tu DSK, entonces puedes descargarlo con Download DSK file y tendrás tu disquete virtual listo para utilizar en tu emulador.

4.- CPCBOX

Como ya os conté en el otro artículo, yo utilizo CPCBOX para probar estas cosas, así que solo tienes que arrancar el emulador, y seleccionar la imagen de tu disquete virtual en la disquetera, como puedes ver en la captura siguiente.
Una vez cargado, puedes ver el contenido desde tu AMSTRAD usando CAT - como siempre -, y ver todos tus ficheros y pruebas ahí listados.
En mi caso, como podéis ver, he estado haciendo bastantes pruebas, y muchas han fallado, pero bueno, al final casi he conseguido tener un método de trabajo que funcione. Para cargar el programa, pidiéndole que cargue el programa a partir de la dirección &4000 (puedes probar a partir de la &1000 que es también típica para códigos binarios en AMSTRAD CPC), pues debes cargarlo en memoria.
Para eso, reservamos memoria, cargamos el binario y mandamos el contador de programa del AMSTRAD a la dirección de carga del código BIN que hemos cargado. Si este no funciona bien, y no hace el RET en el código final, el resultado será que se te cuelga el equipo y hay que apagar y encender. 
Esto es otro tipo de equipo al que tenemos hoy en día con la memoria protegida y arquitecturas preemptivas. Aquí el programa puede quedarse con el flujo de programa.

Conclusión

La gracia de todo este proceso, para mí, era poder programar en AMSTRAD CPC haciendo uso del ASM del Z80 porque este era el lenguaje más potente y la forma de hacer los juegos más bonitos de este equipo, pero por desgracia el Vibe-Coding (Spec-Coding) para el Z80 de AMSTRAD CPC aún no está muy logrado, así que hay que remar mucho. Veremos en siguientes versiones, u otros modelos. Si lo pruebas en algún modelo o versión que te funcione a la primera... ¡házmelo saber!

¡Saludos Malignos!

Autor: Chema Alonso (Contactar con Chema Alonso)  


Entrada destacada

Hacking IA: Jailbreak, Prompt Injection, Hallucinations & Unalignment. Nuestro nuevo libro en 0xWord

Pocas veces me ha hecho tanta ilusión que saliera un nuevo libro en 0xWord como con este libro de " Hacking IA: Jailbreak, Prompt Inje...

Entradas populares