orquestra-qa-agent
v0.9.1
Published
Agente de QA de Orquestra -- corre en una Mac, toma corridas de la cola y reporta resultados vía la API (nunca toca Firestore directo)
Readme
orquestra-qa-agent
Agente de QA de Orquestra. Corre en una Mac (la dedicada a QA, o la misma donde desarrollas), toma corridas de la cola y reporta el progreso paso a paso. Los fallos se convierten en tareas en Orquestra sin duplicarse y se cierran solas cuando el test vuelve a pasar — esa lógica vive en el servidor, no acá.
- Nunca toca la base de datos directo. Habla con la API de Orquestra con un token de servicio propio.
- Cero dependencias. Node ≥ 18, ESM plano,
fetchnativo. - Los logs completos de cada corrida quedan en esta máquina
(
~/.orquestra/qa-logs/<runId>.log); a Orquestra solo viaja el tail (≤3000 chars por paso).
Emparejar (una sola vez por máquina)
- En Orquestra: Workspace → QA → Emparejar máquina → copia el comando.
- En esta Mac:
npx orquestra-qa-agent pair XXXX-XXXX --name "Mac mini QA"El código es de un solo uso (10 min). El agente guarda su token en
~/.orquestra/qa-agent.json (0600) — archivo propio, no el
mcp-config.json del MCP (ese es un contrato compartido con otros
consumidores).
Configurar un proyecto (una vez por repo, ya emparejada la máquina)
Corre esto dentro del checkout real del proyecto -- identifica solo a
qué proyecto de Orquestra pertenece (comparando git remote get-url origin
contra el repoUrl que ya tengan guardado sus distributions) y llena
localPath + los stacks detectados sin que edites nada a mano en la web:
cd /donde/tengas/el/checkout/real
npx orquestra-qa-agent setupSi el repo no matchea ningún proyecto (por ejemplo porque su distribution
todavía no tiene repoUrl guardado), te deja elegir de una lista en vez de
adivinar. También reporta qué detectó en esta Mac (Xcode, adb/emulator,
Docker, caché de navegadores de Playwright) y prueba el acceso de git al
remoto (git ls-remote, sin tocar el checkout) -- si falla, te dice cómo
arreglarlo (SSH o Personal Access Token + credential helper) pero sigue con
la config de todos modos, para que puedas confirmarlo después con
orquestra-qa-agent setup otra vez.
El stack (web/ios/android) lo detecta solo, por el contenido de la
carpeta donde corres setup (package.json → web, .xcodeproj/
.xcworkspace → ios, build.gradle/gradlew → android) -- no depende de
qué sepa correr esta Mac ni de cómo se llame el --profile. Si el checkout
no tiene ninguno de esos marcadores en la raíz, te deja elegir a mano en vez
de adivinar. Solo usa --stack <s> si necesitas forzarlo (caso raro).
Varios agentes en la misma Mac
Si un mismo proyecto tiene varios stacks (web, iOS, Android), no hace falta
--profile para tener un agente por cada uno -- una sola identidad
(un solo pair) puede tener varios agentes, uno por stack, cada uno con
su propio localPath. setup detecta solo el stack por la carpeta desde la
que lo corres y crea/actualiza el agente que le toca -- sin pisar el de otro
stack ya configurado con esa misma identidad:
npx orquestra-qa-agent pair XXXX-XXXX --name "Mac mini QA" # una sola vez
cd /ruta/al/checkout/orquestra-web && npx orquestra-qa-agent setup
# -> detecta "web" solo, crea el agente "web"
cd /ruta/al/checkout/orquestra-ios && npx orquestra-qa-agent setup
# -> detecta "ios" solo, crea el agente "ios" (misma identidad, otro agente)
npx orquestra-qa-agent start # un solo daemon sirve a los dos agentes (uno a la vez)start también detecta el stack de la carpeta desde la que lo corres --
si lo corres dentro de un checkout reconocido, el daemon solo reclama
corridas de ESE stack (con --stack <s> puedes forzarlo, o correrlo fuera
de cualquier checkout para que no tenga límite, como antes). Esto permite
correr dos start con la misma identidad (uno por carpeta, sin
--profile) sin que se peleen por corridas del otro:
# Terminal 1
cd /ruta/al/checkout/orquestra-web && npx orquestra-qa-agent start # solo atiende "web"
# Terminal 2
cd /ruta/al/checkout/orquestra-ios && npx orquestra-qa-agent start # solo atiende "ios"La sección QA del proyecto en la web muestra el estatus de cada agente por separado (no de la máquina) -- así ves ambos corriendo en paralelo sin que se confundan entre sí, aunque compartan la misma máquina/identidad.
--profile (identidad de runner separada, ~/.orquestra/qa-agent-<perfil>.json,
aparece como máquina distinta en Workspace → QA) solo hace falta si además
quieres que el heartbeat/estado de "máquina en línea" de Workspace → QA no
se comparta entre los dos procesos -- para el día a día, dos start por
carpeta (sin perfil) ya corren en paralelo de verdad. setup siempre hace
merge con la config existente del proyecto (lee-modifica-escribe) en vez de
sobreescribirla, así que no borra el agente que otra carpeta/perfil ya
configuró.
Correr
npx orquestra-qa-agent pair de arriba NO deja el comando instalado --
sigue usando npx para todo, o instálalo una vez de forma global:
npx orquestra-qa-agent start # heartbeat 60s + poll de cola 15s
npx orquestra-qa-agent status # con qué runner/workspace está emparejadaCon --profile <nombre> en cualquiera de los dos, opera sobre esa identidad
en vez de la default (ver "Varios agentes en la misma Mac" arriba).
Cada minuto vas a ver "esperando corridas..." en la terminal -- si no ves
nada, algo está mal (revisa status). Si una corrida falla por algo que va
a fallar exactamente igual la próxima vez (sin acceso a git, localPath
roto...), el agente se detiene solo con un mensaje bien visible en vez de
reintentar en silencio para siempre -- arregla lo que diga y vuelve a correr
start. Este caso también manda una notificación in-app a Orquestra
(campana del Topbar en web/iOS) para que no dependas de estar mirando esta
terminal para enterarte.
Para que arranque solo con la Mac (LaunchAgent), instálalo global primero
-- launchd corre en un entorno mínimo y no resuelve bien npx cada vez,
así que ahí sí conviene una ruta fija:
npm install -g orquestra-qa-agent
which orquestra-qa-agent # copia esta ruta para el plist de abajo~/Library/LaunchAgents/me.orquestra.qa-agent.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
<key>Label</key><string>me.orquestra.qa-agent</string>
<key>ProgramArguments</key><array>
<string>/RUTA/DE/which-orquestra-qa-agent</string>
<string>start</string>
</array>
<key>RunAtLoad</key><true/>
<key>KeepAlive</key><true/>
<key>StandardOutPath</key><string>/tmp/orquestra-qa-agent.log</string>
<key>StandardErrorPath</key><string>/tmp/orquestra-qa-agent.log</string>
</dict></plist>launchctl load ~/Library/LaunchAgents/me.orquestra.qa-agent.plistQué corre en cada proyecto
La config vive en Orquestra (sección QA del proyecto): máquina asignada
(o cualquiera), rama, stacks, localPath (el checkout en esta máquina), y en
qué estatus se abren/cierran los bugs. Pasos autodetectados v1:
| Stack | Pasos |
|---|---|
| web/node | npm run lint / npm test / npm run build (los que existan en package.json) + npx playwright test si hay playwright.config.{js,ts,mjs} |
| ios | Detecta scheme (xcodebuild -list) y un simulador disponible (xcrun simctl) → xcodebuild test real. Sin poder detectarlos, cae a xcodebuild build (solo compila) |
| android | Con un dispositivo/emulador conectado (adb devices) → ./gradlew connectedAndroidTest real. Sin ninguno conectado, cae a ./gradlew build (solo compila) |
Antes de los pasos hace git fetch/checkout/pull --ff-only de la rama
configurada. Timeout de 15 min por paso. La cancelación desde la UI se
detecta entre pasos y también a mitad de paso (poll de 10s → SIGTERM).
Revisión con IA (opt-in por agente)
Cada agente puede activar un paso extra al final de la corrida: claude -p
(Claude Code headless, tuyo, autenticado en esta Mac) explora el proyecto y
reporta hallazgos -- no reemplaza lint/test/build, corre después. Los
hallazgos NUNCA se aplican solos: van a Dashboard → Sugerencias de IA para
que los aceptes o descartes a mano, igual que las sugerencias de changelog.
Actívalo desde la web (tarjeta "Agentes" en la sección QA del proyecto,
checkbox "Revisión con IA") -- default apagado a propósito: cada corrida con
esto activado tiene un costo real contra tu plan/cuenta de Claude (no algo
que factura Orquestra), confirmado con pruebas reales antes de construirlo
(ver CLAUDE.md para el detalle del contrato de claude -p). Requiere
tener el CLI de Claude Code instalado en la Mac que hace de runner
(claude.ai/code) -- si no está, ese paso queda como "Error" con el
mensaje explicando qué instalar, el resto de la corrida sigue normal.
Si una corrida viene acotada a una tarea o módulo específico (desde el
selector "Correr con..." en la web, o taskId/moduleId en create_qa_run
del MCP), la revisión con IA se enfoca en eso en vez de auditar todo el
proyecto -- útil para "corre QA de lo que acabo de hacer" en vez de una
revisión completa cada vez.
Agentes de Seguridad y Performance (23 ago 2026)
Además de kind='qa', un agente puede ser kind='security' o
kind='performance' -- se crean desde la web (tarjeta "Agentes", no desde
setup, que solo maneja QA) o con create_agent del MCP. Ambos corren sobre
el mismo localPath/rama que un agente de QA, pero solo tienen lógica real
para stack web por ahora:
| Kind | Pasos | Requiere |
|---|---|---|
| security | npm audit (siempre, si hay package.json) + gitleaks (si está instalado) | gitleaks es una herramienta externa -- brew install gitleaks. Sin ella, el paso queda visible como "Falló" con instrucciones, en vez de desaparecer en silencio. |
| performance | Tamaño de build (npm run build + du -sk sobre dist/build/.next/out) + Lighthouse | Lighthouse corre vía npx lighthouse contra agent.perfUrl (una URL YA VIVA, ej. staging/prod -- no levanta un server local) -- necesita Chrome instalado en esta Mac. |
Ambos kinds reportan hallazgos reales (findings, antes reservado y sin uso)
además del log resumido -- a diferencia de los pasos de QA (que solo pasan/
fallan por exit code), estos parsean la salida real (JSON de npm audit/
gitleaks/Lighthouse) para decidir el estatus: security falla con
cualquier vulnerabilidad high/critical o secreto detectado; performance
falla si el build supera agent.maxBundleSizeKb (default 5000) o el score
de Lighthouse cae bajo agent.minPerfScore (default 50). Los secretos NUNCA
viajan en texto plano -- gitleaks corre con --redact y los findings solo
incluyen archivo+línea+regla, nunca el valor real.
Mismo mecanismo de bugs-como-tareas que QA (huella + auto-cierre), con
tags distintos (['security']/['performance'] en vez de ['qa']) --
ver orquestra-infra/functions/api/lib/agents.mjs.
Pendiente (documentado, no construido)
- Automatización de corridas por push/agenda. Nunca se construyó -- el
único rastro que quedaba era
qaConfig.triggers/qaConfig.integrationId(campos write-only, nunca leídos en ningún lado), y se eliminaron al mover el resto deqaConfigaagents(config por agente, no por proyecto; ese doc en sí se generalizó después aagentsConfig-- verorquestra-infra/CLAUDE.md). Si se retoma, probablemente el diseño correcto ahora es por-agente (cada agente ya sabe su propiodistributionId/repo) en vez de un solo trigger a nivel proyecto -- un cron local que evalúe la agenda y auto-encole (POST /v1/agent-runsconidempotencyKey) sigue siendo la forma más simple de implementarlo sin infraestructura nueva.
