Si trabajas en tecnología, probablemente hayas notado la repentina explosión de "notetakers de IA". Cada vez que te unes a una llamada de Zoom o Google Meet, dos o tres bots de navegadores invisibles (headless) se unen como participantes.
Sinceramente, me cansé de eso. Se siente intrusivo, interrumpe el flujo de la reunión y los departamentos de TI corporativos odian las implicaciones de privacidad de enviar audio crudo de reuniones directivas a nubes de terceros aleatorias. Además, a pesar de tener una transcripción, todavía me encontraba pasando 30 minutos traduciendo manualmente la discusión en tickets de Jira o Linear perfectamente definidos.
Así que decidí construir Plan AI.
En lugar de construir otro bot, construí un grabador de audio de sistema local, centrado en la privacidad, que orquesta un complejo pipeline de IA asíncrono. Genera automáticamente tickets de ingeniería, documentos en Markdown y diagramas de arquitectura en Mermaid.js.
Si te encanta el diseño de sistemas, las colas distribuidas, las bases de datos vectoriales y las herramientas de IA de vanguardia (como Model Context Protocol), prepárate un café. Aquí tienes un desglose técnico masivo de cómo funciona realmente este monorepositorio por debajo.
1. Derrotando al "Bot" (Audio del Sistema vía Electron)
El mayor obstáculo del producto fue deshacerse del participante virtual de la reunión. La solución fue capturar el audio del sistema operativo directamente.
Aquí está la diferencia fundamental entre el enfoque estándar de la industria y la arquitectura de Plan AI:
La Forma Antigua (Bots Intrusivos)
El Estilo Plan AI (Captura Nativa)
Utilicé Electron para la aplicación de escritorio. Aprovechando las APIs nativas de escritorio (desktopCapturer y getUserMedia), la aplicación escucha la salida del sistema (lo que escuchas por los altavoces) y la entrada del micrófono simultáneamente. Los flujos de audio se mezclan localmente.
El desafío aquí es el consumo excesivo de memoria (memory bloat). No puedes simplemente mantener un archivo WAV sin comprimir de 2 horas en la RAM. La aplicación de Electron escribe el flujo de audio en el disco local en fragmentos utilizando un MediaRecorder, produciendo un archivo WebM/Opus optimizado. Una vez que termina la reunión (o periódicamente para la transcripción en vivo), el archivo se sube de forma segura al backend a través de un stream multiparte para evitar bloquear el servidor Node.
Para completar el ecosistema, también construí una aplicación móvil en React Native (Expo) para reuniones en persona, y una plataforma web en React donde puedes chatear con un "Asistente de Reunión en Vivo" (que consulta la transcripción cada 15 segundos) mientras la reunión aún está en curso.
2. El Orquestador Asíncrono (BullMQ + Redis)
Procesar archivos de audio grandes y consultar múltiples LLMs es increíblemente intensivo en CPU y red. Si intentas procesar un archivo de audio de 100MB de forma síncrona en una ruta de Express, el event loop de Node.js se bloqueará y tu servidor desconectará las peticiones inmediatamente.
Diseñé un pipeline distribuido usando BullMQ y Redis. Cuando la aplicación de Electron termina de subir el audio, el controlador de Express devuelve inmediatamente un 200 OK y envía un trabajo (job) a Redis.
// Pushing heavy tasks to the background export async function queueAudioProcessing(meetingId: string, filePath: string) { await meetingQueue.add('process-audio', { meetingId, audioPath: filePath, }, { attempts: 5, backoff: { type: 'exponential', delay: 5000 }, removeOnComplete: true, }); }
A partir de ahí, el worker en segundo plano toma el trabajo y orquesta un pipeline de múltiples pasos:
- Transcripción (Deepgram): El audio se envía a la API de Deepgram. Elegí Deepgram porque es increíblemente rápido y maneja la diarización de hablantes (Speaker 1, Speaker 2) por defecto.
- Biometría de Voz (SpeechBrain): Depender únicamente de Deepgram para la identificación de hablantes en múltiples reuniones no funciona. Así que levanté un microservicio local en Python usando FastAPI y SpeechBrain. El worker de Node envía fragmentos de audio a Python, el cual extrae los "voice embeddings" y verifica si el "Speaker 1" es realmente el CTO.
- Resiliencia y Rate Limiting: Dado que estamos consultando APIs externas (Deepgram, Jira, Linear), BullMQ me permite implementar límites de velocidad estrictos (rate limiting) y Dead Letter Queues (DLQ). Si la API de Jira se cae, el trabajo se pausa y reintenta exponencialmente sin perder el payload de audio.
3. OpenRouter y BYOK (Bring Your Own Key)
Al construir una aplicación de IA, codificar (hardcode) directamente gpt-4o o claude-3.5-sonnet es una receta para el desastre. Las APIs se caen, las tarifas cambian y algunas tareas requieren diferentes niveles de inteligencia.
En lugar de atarse a OpenAI o Anthropic directamente, Plan AI utiliza OpenRouter como una puerta de enlace (gateway) de LLM unificada. En el backend, enrutamos dinámicamente las tareas según sus requisitos cognitivos específicos:
-
Investigación Agéntica: Enrutado a
openai/gpt-4o-mini(increíblemente rápido y rentable para recopilar contexto rápido y búsquedas semánticas antes de la creación de tareas). -
Extracción Final de Tareas: Enrutado a
anthropic/claude-opus-4.7(caro, pero inigualable para comprender profundamente el contexto del proyecto y estructurar tickets perfectamente definidos). -
Diagramas Arquitectónicos: Enrutado a
anthropic/claude-sonnet-4.6(el mejor modelo absoluto para codificar y generar diagramas complejos de Mermaid.js). -
Características de Imagen: Enrutado a
black-forest-labs/flux.2-klein-4b(un modelo de imagen de alto rendimiento que reemplazó a DALL-E para nuestras funciones visuales). -
Lógica de Respaldo (Fallback): Si un modelo o proveedor principal se cae, utilizamos las
providerOptionsde OpenRouter para recurrir automáticamente a modelos alternativos, garantizando que las colas en segundo plano nunca se atasquen.
Además, Plan AI utiliza una arquitectura BYOK (Bring Your Own Key). En lugar de que la plataforma pague por el uso de la API y cobre un margen, los usuarios introducen sus propias claves de OpenRouter por Workspace. Esto reduce drásticamente los costes operativos del SaaS y garantiza la privacidad de los datos.
4. Memoria Semántica (Base de Datos Vectorial Qdrant)
Tener una transcripción en bruto no es suficiente para generar buenos tickets de Jira. Si un desarrollador dice "Voy a arreglar el bug de autenticación", el LLM necesita saber qué es exactamente ese "bug de autenticación".
Para resolver esto, integré Qdrant, una base de datos vectorial de código abierto. Cada vez que termina una reunión, la transcripción se divide en fragmentos, se vectoriza utilizando un modelo de embeddings y se almacena en Qdrant.
Cuando el proceso en segundo plano extrae las tareas, primero realiza una búsqueda semántica. Recupera decisiones arquitectónicas pasadas y el contexto de proyectos de reuniones anteriores, inyectándolos en el prompt del LLM. Esto transforma un output genérico en tickets de ingeniería altamente específicos con criterios de aceptación exactos.
5. El Compañero Móvil (Expo 55 y React Native)
Mientras que la aplicación de escritorio captura las llamadas virtuales, las reuniones presenciales requieren un enfoque diferente. Construí la aplicación móvil de apoyo utilizando la última versión de Expo SDK 55.
Si no has tocado React Native en unos años, el ecosistema se ha transformado por completo. Usando Expo Router, el enrutamiento basado en archivos hace que navegar por la app móvil se sienta exactamente igual que Next.js. Todo el código base está estrictamente tipado con TypeScript, compartiendo los mismos tipos exactos generados (api.d.ts) que la aplicación web en React y el backend.
Esto significa que recuperar una transcripción en el móvil, renderizar el chat del Asistente en Vivo y mostrar las tareas generadas comparte el 90% del modelo mental con el frontend web. Arquitectura limpia, cero tipado manual y una mantenibilidad increíble.
6. Vanguardia en DevEx: GitNexus (MCP)
Este es un monorepositorio grande, y construirlo en solitario requirió un gran uso de asistentes de código de IA (como Cursor y Cline). Pero los LLMs alucinan cuando no entienden la arquitectura completa del código.
Para solucionar esto, Plan AI incluye un servidor Model Context Protocol (MCP) a través de GitNexus. GitNexus indexa todo el monorepositorio en una base de datos de grafos local.
Cuando le pido a mi agente de IA "Modifica el servicio de generación de diapositivas", el agente no se limita a adivinar. Llama automáticamente a gitnexus_impact() para ver el radio de impacto (blast radius) del cambio, y a gitnexus_query() para entender el flujo de ejecución exacto desde el controlador de Express hasta el worker de BullMQ. Hace que programar con IA sea increíblemente seguro y determinista.
7. Uniendo la Estrategia y el Código (Repomix y GitHub)
El objetivo final de Plan AI no es solo escribir tickets; es eliminar por completo la fricción entre los roles no técnicos (Product Managers, Diseñadores) y la ejecución técnica (Desarrolladores y Agentes de IA).
Cuando un Product Manager termina una reunión, Plan AI genera automáticamente los tickets de ingeniería y los envía directamente a GitHub Issues (o Linear/Jira). Pero para que esos tickets sean procesables de inmediato por un asistente de código de IA (como Cursor o Copilot), integramos Repomix.
Usamos un simple script (yarn repomix) que empaqueta todo el monorepositorio en un único archivo Markdown altamente optimizado (ignorando tests, builds y node_modules).
El flujo de trabajo es mágico:
- El PM habla en la reunión. Plan AI crea un GitHub Issue altamente técnico con criterios de aceptación exactos.
- El desarrollador asigna el issue a su asistente de código de IA.
- El asistente de IA lee el issue, consume el archivo
repomix.mdpara entender instantáneamente todo el contexto del monorepositorio y redacta la Pull Request (PR).
Aquí está el flujo de cómo Plan AI actúa como capa de traducción entre la conversación humana y el código generado por IA:
8. Extrema Seguridad de Tipos (De Prisma a Swagger)
Cuando lidias con un backend, una aplicación web React, una app móvil React Native y una aplicación de escritorio Electron, mantener las interfaces de las APIs manualmente es una pesadilla. Si el backend cambia userName a username, 3 frontends diferentes se rompen.
Implementé un pipeline automatizado para la seguridad de tipos (type safety):
- Prisma es la única fuente de verdad para el esquema de la base de datos.
- Prisma alimenta los controladores TSOA (TypeScript OpenAPI) en el backend.
- TSOA genera automáticamente una especificación
swagger.jsonbasada en decoradores.
// Backend Controller @Route("api/tasks") export class TaskController extends Controller { @Get("{id}") public async getTask(@Path() id: string): Promise<TaskResponse> { return taskService.findById(id); } }
- Escribí un único script (
yarn update) que migra la BD, regenera el archivo swagger y ejecutaopenapi-typescriptpara sincronizar un archivoapi.d.tsen los tres frontends simultáneamente.
Esto eliminó por completo el temido error TypeError: undefined is not an object en todo el stack.
9. Convirtiéndose en Open Core (BUSL-1.1)
Debido a que esta aplicación pide permiso para grabar el audio del sistema, la confianza es primordial. No podía simplemente publicar un binario cerrado y esperar que los ingenieros lo instalaran.
Decidí abrir el núcleo (open source) del proyecto bajo la Licencia Business Source (BUSL-1.1), la cual se convierte en AGPLv3 después de 4 años. Esto permite a cualquiera auditar el código fuente de Electron, verificar que realmente prioriza la privacidad (sin spyware) e incluso alojar toda la infraestructura (self-host) utilizando Docker.
Si te encanta la arquitectura de sistemas, la orquestación RAG o simplemente quieres una herramienta que escriba tus tickets de Jira localmente por ti, puedes revisar el código fuente aquí:
Repositorio de GitHub: Plan AI
Sitio Web y Demo
¡Me encantaría saber cómo manejáis el procesamiento asíncrono de audio o la seguridad de tipos en vuestros propios monorepositorios masivos! Házmelo saber en los comentarios.
