Integraciones

Integración con CI

Dispara evaluaciones desde tu pipeline y usa el resultado como gate de despliegue.

Verica se integra con CI al revés que la mayoría de las herramientas de evals. El eval vive en Verica — el golden set, los criterios, los jueces, la condición de aprobación. El repositorio solo tiene el prompt. CI no define la evaluación: la dispara por ID.

La consecuencia práctica es que el único secreto que tu pipeline necesita es el token de Verica. No hay que inyectar OPENAI_API_KEY en el runner.

Crear un token

En Configuración del proyecto → API Keys: "Tokens para disparar evals de este proyecto desde tu CI/CD. El token se muestra una sola vez al crearlo."

El diálogo pide un Nombre (por ejemplo ci-github) y los Permisos:

PermisoPara qué
Ejecutar (run)Disparar ejecuciones de un eval.
Leer (read)Consultar el estado y los resultados de una ejecución.
Ingesta de trazas (ingest)Enviar trazas desde tu aplicación.

Para CI hacen falta run y read, que vienen marcados por defecto.

El token tiene la forma vk_live_… y se muestra una sola vez: "Guárdalo ahora: no se vuelve a mostrar." Verica guarda solo su hash y un prefijo visible, así que la lista te deja identificarlo sin poder recuperarlo.

Guárdalo en tu CI como VERICA_TOKEN. Puedes revocarlo cuando quieras — "El token dejará de funcionar de inmediato en tu CI/CD."

Los tokens están atados a un proyecto. Un token del proyecto A no puede disparar un eval del proyecto B: la respuesta es un 403. La razón es el radio de daño — una ejecución gasta la credencial BYOK de ese proyecto.

El CLI

npx @verica-app/cli run --eval eval_8x2k9d --prompt prompts/agente.txt --junit report.xml

El paquete es @verica-app/cli, MIT, requiere Node 20 o superior y expone un único comando: run.

"No hay nada de propiedad intelectual en el cliente: el motor, los graders, el gate y la criptografía corren todos del lado del servidor, detrás de la API del token." El CLI es inspeccionable a propósito — leerlo revela el contrato HTTP público y nada más.

Variables de entorno

  • VERICA_TOKEN — obligatoria.
  • VERICA_BASE_URL — solo para instalaciones propias o desarrollo. Por defecto https://my.verica.app.

Opciones

Qué ejecutar

OpciónQué hace
--eval <id>El ID público del eval (eval_…). Obligatorio, salvo que uses --manifest.
--manifest <archivo>Un .verica.yml con varios evals.
--prompt <archivo>El archivo del prompt de usuario.
--system-prompt <archivo>El prompt de sistema, independiente y opcional.
--tools <archivo>Definiciones de herramientas en JSON: formato plano de Verica o formato de OpenAI.
--model <modelo>Opcional. Si lo omites, se usa el modelo de la última ejecución del eval.
--sampling <archivo>Parámetros de sampling en JSON.

Resultado y gate

OpciónQué hace
--junit <archivo>Escribe un reporte JUnit XML.
--junit-mode <modo>rows (por defecto) o gate.
--jsonSalida legible por máquina en stdout.
--threshold <0..1>Sobreescribe el pass rate mínimo del gate.
--baseline-ref <ref>Compara contra la última ejecución de esa rama.
--baseline-run <id>Compara contra una ejecución concreta (run_…).
--no-waitDispara y sale con código 0, sin esperar ni aplicar el gate.

Reutilización

OpciónQué hace
--reuse-if-unchangedReutiliza una ejecución reciente si nada cambió.
--reuse-max-age <horas>Antigüedad máxima aceptable. Por defecto 24, máximo 720.
--reuse-same-refSolo reutiliza ejecuciones de la misma rama.

Procedencia y transporte

--git-sha, --git-ref y --git-repo-url se deducen solos de las variables de GitHub Actions o GitLab; sirven para que la ejecución enlace al commit y a la rama. --poll-interval (3 s), --timeout (1800 s) y --base-url completan la lista.

--wait sigue aceptándose pero ya no hace nada: esperar es el comportamiento por defecto. Todos los ejemplos históricos lo incluyen; es inofensivo.

Códigos de salida

CódigoSignifica
0Pasó.
1El gate falló.
2Error de validación o de transporte.

Con varios evals, el CLI devuelve el peor de todos.

Una ejecución sin condición de aprobación definida sale con 0 y un aviso por stderr: "no pass condition defined; gating disabled (exit 0)". Si quieres que CI bloquee, define el gate.

Estos tres códigos son estables. El resto de la superficie del CLI — flags, formato JSON, salida JUnit — todavía se está asentando: el paquete es 0.x y ahí el que rompe es el minor. Conviene fijar "@verica-app/cli": "~0.1".

La condición de aprobación

El gate se configura en la interfaz, en la pestaña Configuración del eval, no en YAML. "Define cuándo una ejecución por CI 'pasa' y desbloquea el merge. Vacía → las ejecuciones siempre pasan."

Son tres dimensiones que se combinan con Y:

Pass rate mínimo

Un piso absoluto: pasa si el pass rate ≥ X. Al lado del campo, Verica muestra el pass rate de la última ejecución y el promedio de las últimas cinco, para que el número no se elija a ciegas.

--threshold lo sobreescribe desde el CLI.

No-regresión

Bloquear si baja respecto de una referencia: la última ejecución en la rama base, una ejecución fija o la última que pasó. Con una tolerancia en puntos porcentuales.

Confiabilidad

Cuántas filas pueden quedar rotas: exigir ejecución completa (0 errores) o permitir hasta un porcentaje.

"Un 'error' es una fila que no se pudo ejecutar o evaluar, no una fila que se ejecutó y no cumplió el criterio. Para eso usa 'Pass rate mínimo'."

El panel resume la condición en una frase: "Pasa si: pass rate ≥ 90% y no baja más de 2 pts vs. la última ejecución en la rama base y 0 errores de ejecución."

El veredicto se calcula en el servidor cuando la ejecución termina y queda congelado con ella. El CLI no lo recalcula: lo lee.

--reuse-if-unchanged no se puede combinar con --threshold, --baseline-ref ni --baseline-run. El CLI lo rechaza antes de salir a la red.

Formatos de salida

JUnit

--junit-mode rows (por defecto) emite un caso de prueba por caso del golden set: los que no pasaron son failure, los N/A son skipped.

--junit-mode gate emite un caso por dimensión del gate, con mensajes como pass rate 94.0% vs. min 90.0%.

El estado del job lo decide el código de salida, no la cantidad de failure en el XML: un eval al 92% tiene un 8% de casos fallando por diseño. El modo gate existe para los CI que fallan ante cualquier <failure> en un reporte JUnit.

JSON

--json escribe un array en stdout, un elemento por eval, con runId, resultUrl, status, passed, gated, totals, gateResult, model y judge. Es un contrato público, congelado por tests.

El resumen legible va a stderr, así que stdout queda limpio para canalizarlo:

→ 50 casos · judge=rubric+llm · model=gpt-4.1-mini
✓ 47 passed  ✗ 3 failed   score 0.91

Ejemplos por plataforma

on: { pull_request: { paths: ['prompts/**'] } }
jobs:
  eval:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: verica-app/run-action@v1
        with:
          token: ${{ secrets.VERICA_TOKEN }}
          manifest: .verica.yml

Con un solo prompt, sin manifiesto:

      - uses: verica-app/run-action@v1
        with:
          token: ${{ secrets.VERICA_TOKEN }}
          eval: eval_8x2k9d
          prompt: prompts/support-agent.txt
          model: gpt-4.1-mini
          baseline-ref: main

La acción envuelve al CLI, deja el reporte JUnit (verica-results.xml por defecto) y publica un comentario en el pull request con una tabla de eval, gate y pass rate, actualizándolo en cada push. El comentario es lo único específico de GitHub; puedes desactivarlo con comment: false.

verica:
  image: node:22
  rules: [{ changes: ['prompts/**'] }]
  script:
    - npx @verica-app/cli run --manifest .verica.yml --junit report.xml
  artifacts:
    when: always
    reports:
      junit: report.xml

Guarda VERICA_TOKEN como variable enmascarada de CI/CD. GitLab renderiza el reporte JUnit dentro del merge request.

jobs:
  verica:
    docker: [{ image: cimg/node:22.0 }]
    steps:
      - checkout
      - run: npx @verica-app/cli run --manifest .verica.yml --junit report.xml
      - store_test_results: { path: report.xml }

Guarda VERICA_TOKEN como variable de entorno del proyecto.

pipeline {
  agent { docker { image 'node:22' } }
  environment {
    VERICA_TOKEN = credentials('verica-token')
  }
  stages {
    stage('eval') {
      steps { sh 'npx @verica-app/cli run --manifest .verica.yml --junit report.xml' }
    }
  }
  post { always { junit 'report.xml' } }
}

El prompt: cómo viaja y cómo se versiona

El CLI lee los archivos y manda su contenido en el cuerpo de la petición. Los tres campos son independientes y opcionales, y lo que no mandes se hereda de la versión actual: pasar solo --system-prompt versiona el prompt de sistema y deja intactos los mensajes y las herramientas.

Del lado del servidor:

  1. Se combinan los campos enviados sobre la versión actual.
  2. Se compara el contenido resultante. Si es idéntico, se reutiliza la versión; si no, se crea una nueva.
  3. El modelo y los parámetros de sampling no entran en esa comparación — viajan en la ejecución. Cambiar solo el modelo reutiliza la versión del prompt y crea una ejecución nueva.
  4. Siempre se encola una ejecución. El deduplicado decide si nace una versión, nunca si se ejecuta.

La respuesta trae el número de versión y si fue nueva, y el CLI lo imprime: prompt v7, new version.

La procedencia (commit, rama, repositorio, que vino de CI) se estampa en la ejecución, no en la versión. Por eso un cambio de modelo, que reutiliza la versión, igual deja registrado su commit.

Validaciones antes de ejecutar

Verica responde 400 con un código estable, antes de gastar un token, si:

  • El prompt usa una variable {{ }} que el golden set no tiene.
  • El modelo no está en la tabla de precios (en CI esto sí es estricto, porque de ahí se deduce el proveedor).
  • El workspace no tiene una credencial BYOK de ese proveedor en el proyecto del eval.

Prompt gestionado desde el repo

Desde Conectar con CI, en la página del eval, puedes marcar el prompt como repo-managed indicando su ruta. A partir de ahí git es la fuente de verdad y la interfaz lo muestra en solo lectura: "Repo-managed · {ruta}".

Ese mismo panel te da el snippet ya armado, con el ID del eval y la URL base.

Varios prompts: .verica.yml

evals:
  - id: eval_8x2k9d
    prompt: prompts/support-agent.txt
    systemPrompt: prompts/support-system.txt
    model: gpt-4.1-mini
  - id: eval_3n7q1p
    prompt: prompts/router.txt
    tools: prompts/router-tools.json

Solo id es obligatorio en cada entrada. tools acepta una ruta o un array en línea. --model desde la línea de comandos sobreescribe el de todas las entradas.

Reutilizar ejecuciones

--reuse-if-unchanged evita pagar dos veces por lo mismo. Verica considera que nada cambió cuando coinciden la versión del prompt, el modelo, los parámetros de sampling, el snapshot del dataset y los graders. El gate no forma parte de esa comparación.

Solo se reutilizan ejecuciones completadas, nunca parciales ni fallidas, y por defecto de las últimas 24 horas (máximo 720). No existe un "para siempre" a propósito: la reutilización no puede ver la deriva del proveedor detrás de un identificador de modelo estable.

Cuando hay reutilización, la API responde 200 en lugar de 202, el CLI marca reused: true, y el evento aparece en el historial del eval con la insignia reutilizada. Sin eso, una reutilización sería invisible.

La API

Si prefieres no usar el CLI, son tres endpoints:

EndpointPermisoQué hace
POST /api/v1/evals/:id/runsrunDispara una ejecución. 202 nueva, 200 reutilizada.
GET /api/v1/runs/:idreadEstado, veredicto, totales y gate.
GET /api/v1/runs/:id/resultsreadEl detalle por caso.

La autenticación es Authorization: Bearer <token>. Los errores son 401 missing_token, 401 invalid_token, 403 insufficient_scope y 403 project_forbidden.

GET /runs/:id/results devuelve también la configuración congelada de los criterios que calificaron — pero solo la de los criterios determinísticos. Las configuraciones de los jueces llevan consignas y no se exponen.

Siguientes pasos

En esta página