Verax

Verax: el cuerpo de agente responsable. Puerta, registro de decisiones, recibo, conciliación. Apache-2.0.

Documentación

Verax

El cuerpo que un agente consulta antes de actuar.

Listado en: npm · Glama · MCP Registry · MCP Market · mcp.so · Docker Hub · Zenodo

agora

Verax es un servidor MCP que se sitúa entre un agente y sus herramientas. Cada llamada a una herramienta pasa por una puerta de políticas y deja un registro de decisión firmado antes de que se ejecute nada; cada llamada que se ejecutó deja una fila de efecto que se concilia con su registro después. Una denegación se registra igual que una aprobación. Una llamada que la política no decide por sí sola se retiene hasta que un operador en esta máquina la apruebe. El libro mayor permanece en la máquina donde se ejecuta el cuerpo, y el cuerpo solo se abre cuando su autorización está configurada: no hay token por defecto.

Rómpelo, y pagamos. USD 100 por cada informe válido de una forma de que la cuenta del agente logre que se permita una llamada denegada, ejecute una llamada sin registro de decisión, o cambie el código, las claves o el libro mayor del servicio. El presupuesto es de USD 500 en total. Términos: SECURITY.md.

Por VERAX Teknoloji. Proyectos hermanos: Conarium · Tugra · Cedulon. Los registros de decisión usan el formato de registro de Cedulon.

Verlo en acción

npx @verax-ai/body demo

verax demo in a terminal: an allowed memory write, a signed refuse, and a payment held until the operator answers y and types the amount

La grabación es la salida de una ejecución en una terminal donde la pregunta de aprobación se respondió y y se escribió el monto. Esa ejecución tomó alrededor de un segundo; se reproduce lentamente aquí para que pueda leerse.

Lo que imprime, sin una terminal para responder la pregunta de aprobación:

verax demo

memory.put / memory.get
  allowed; two signed records

message.send -> ops@blocked.test
  refused egress-blocked (signed)
  ref 6c6e4925-b769-4a8b-8fc4-e2443613a5b6

spend 100 minor USD sample-merchant
  held
  no terminal to ask, so it stays held (run this in a terminal to be asked)

audit.explain of the refuse
  finding none
  trust-root own-key
  chain and signatures read back

records  5
effects  3
ledger   removed on exit (run with --keep to keep it and check it with verax verify)

Not shown here: data masking arrives with a downstream server such as Conarium; statement reconciliation needs a real statement (verax reconcile).

Node 22.6 o más reciente, @verax-ai/body 0.2.1 o posterior. El comando registra una escritura y lectura de memoria permitidas, una denegación firmada de un mensaje a un host fuera de la lista de políticas, y un pago retenido para el operador en esta máquina (aprobado cuando la terminal responde y y luego escribe el monto, 100; hasta 0.5.0 la demo no imprimía esa segunda pregunta).

--keep deja el libro mayor temporal en disco. verax verify <dir> lo lee de vuelta sin un cuerpo, como en Leer el libro mayor de vuelta sin nosotros.

Las mismas reglas, animadas

Cuatro episodios cortos muestran la misma puerta, con personajes en lugar de una terminal. Son escenarios de muestra: las escenas están dibujadas en three.js y las voces se generan con ElevenLabs.

Episodio 1, "$1,850": un pago se retiene hasta que una persona lo aprueba en un teléfono, y cambiar un centavo en el registro rompe su firma.

https://github.com/user-attachments/assets/772ae1c4-2697-47a0-a228-36f0508b0d93

Episodio 2, "Sin regla, no hay paso": una llamada sin regla se deniega, la misma llamada bajo un nuevo nombre se deniega de nuevo, y ambas denegaciones están firmadas.

https://github.com/user-attachments/assets/4fb86627-3310-4f10-b1a9-059d8fcffb28

Episodio 3, "La palanca roja": un operador detiene el cuerpo, cada llamada posterior se deniega y firma, y una llamada que ya estaba en ejecución no se corta.

https://github.com/user-attachments/assets/8d19eed9-3359-46b3-bd77-f2b1b1c4dd75

Episodio 4, "¿Quién aprobó?": un gasto retenido espera a verax approve en la máquina, el agente no puede aprobarlo, y el id de operador del aprobador entra en el registro.

https://github.com/user-attachments/assets/0b8aade4-a970-4b63-835e-4837e2a39cc9

Conecta tu agente

verax install y verax approve elevados ejecutan una copia de este programa que solo un administrador puede cambiar; una copia que tu cuenta pueda cambiar se deniega. En Windows, un CLI elevado approve es la forma de aprobar hasta que se libere el panel de passkey. Debe ejecutarse desde una cuenta de administrador separada, no esta cuenta elevada, porque un shell elevado del mismo usuario hereda las variables de entorno y el perfil de PowerShell de ese usuario, que el agente puede configurar. Limpia NODE_OPTIONS en ese shell (Remove-Item Env:NODE_OPTIONS). Inicia el PowerShell de esa otra cuenta con -NoProfile (un shell elevado de otro modo ejecuta tu $PROFILE, que tu cuenta puede cambiar):

npm install -g --prefix "$env:ProgramFiles\verax-cli" @verax-ai/body
& "$env:ProgramFiles\verax-cli\verax.cmd" install

En Linux y macOS, con un Node propiedad de root (el /usr/bin/node de la distribución, o /opt/verax-node/<dir>/bin/node; el instalador imprime esos pasos cuando el Node desde el que se inició puede ser cambiado por tu cuenta). No inicies un comando elevado con env node:

sudo npm install -g --prefix /opt/verax-cli @verax-ai/body
sudo /usr/bin/node /opt/verax-cli/lib/node_modules/@verax-ai/body/dist/cli.js install

El comando instala @verax-ai/body desde el registro npm en un directorio propiedad del administrador después de verificaciones de firma, ejecuta ese Node, y mantiene el libro mayor bajo una cuenta de servicio. En Windows el token del agente es %ProgramData%\Verax\agent-token\<your SID>\agent.token (Administrators y SYSTEM tienen control total, tu SID puede leer el archivo y leer-ejecutar el directorio). En Linux y macOS un proceso hijo que se ejecuta como tu uid escribe ~/.verax/agent.token desde su stdin. Imprime la línea de Claude Code que lee ese archivo. ¿Puerto 8787 ocupado? verax install --port 8797. Node debe ser el instalador para todos los usuarios de nodejs.org en Windows; un Node que tu cuenta pueda reescribir se deniega. En macOS el remedio extrae el tarball oficial como root en /opt/verax-node (root:wheel, no escribible por grupo u otros). En Linux el mismo lugar, /opt/verax-node (root:root), que SELinux etiqueta usr_t. En sistemas SELinux la instalación requiere Node etiquetado bin_t o usr_t (el Node de la distribución lo está; un tarball bajo /usr/local/lib no lo está) e imprime la corrección de una línea. El servicio luego se ejecuta en unconfined_service_t. La cuenta de servicio y los permisos de archivo son el límite.

Aprueba una llamada retenida con verax approve. El panel de passkey (verax desktop) aún no está liberado. En Windows ejecuta la aprobación desde una cuenta de administrador separada, no esta cuenta elevada, en un PowerShell -NoProfile después de Remove-Item Env:NODE_OPTIONS: & "$env:ProgramFiles\verax-cli\verax.cmd" approve. Linux y macOS, nombrando el Node propiedad de root: sudo /usr/bin/node /opt/verax-cli/lib/node_modules/@verax-ai/body/dist/cli.js approve o sudo /opt/verax-node/<dir>/bin/node /opt/verax-cli/lib/node_modules/@verax-ai/body/dist/cli.js approve. Desinstala de la misma manera, con uninstall en lugar de approve.

Para probarlo en tu propio usuario, que no es un límite:

verax init --local ~/.verax
verax serve --env-file ~/.verax/verax.env
claude mcp add --transport http verax http://127.0.0.1:8787/mcp --header "Authorization: Bearer $(cat ~/.verax/local-issuer/agent.token)"

El token puede leer y escribir memoria a través de la puerta; no puede aprobar. La política incluida deniega spend hasta que agregues una regla para ello; una llamada que tu política retenga espera a verax approve en esta máquina. Consulta docs/THREAT_MODEL.md.

Con Conarium

@verax-ai/body 0.2.2 y posterior acepta --with-conarium. 0.2.1 no lleva la bandera. La bandera tiene npx descargar @conarium-ai/core desde npm y ejecutarlo como proceso hijo; eso necesita red.

Conarium enmascara las filas, y su política de muestra deniega su tabla public.secrets. Verax pone cada llamada a través de la misma puerta que sus propias herramientas, mantiene un registro firmado y un hash de la respuesta, y deniega una herramienta descendente que la política no nombre antes de que el hijo vea la llamada. Cuando Conarium responde con un error, el cuerpo le dice al llamante que lo hizo, no lo que dijo.

Lo que imprime, sin una terminal para responder la pregunta de aprobación:

verax demo

memory.put / memory.get
  allowed; two signed records

message.send -> ops@blocked.test
  refused egress-blocked (signed)
  ref 6c6e4925-b769-4a8b-8fc4-e2443613a5b6

spend 100 minor USD sample-merchant
  held
  no terminal to ask, so it stays held (run this in a terminal to be asked)

conarium.query customers
  allowed; masked by Conarium before the rows left it
  measured [MASKED_PII] on every email and card

conarium.query public.secrets
  allowed by this gate; Conarium answered with an error and no rows
  recorded as a failed call

conarium.list_tables
  refused no-rule (signed)
  refused by this gate; the downstream server never saw the call

audit.explain of the refuse
  finding none
  trust-root own-key
  chain and signatures read back

records  8
effects  5
ledger   removed on exit (run with --keep to keep it and check it with verax verify)

Not shown here: a real database (these are Conarium's sample rows); statement reconciliation needs a real statement (verax reconcile).

Qué incluye

PaqueteQué es
@verax-ai/bodyEl servidor MCP y el comando verax: serve, install, uninstall, init, doctor, approve, operator, reconcile, witness, halt, resume, unlock (desktop aún no está liberado).
@verax-ai/proxyEl proxy de decisión sobre el que se construye el cuerpo: política, registros firmados, libro mayor, explain, conciliación.
@verax-ai/inventoryEl documento de roster que un cuerpo sirve y que los paneles listan, con su analizador estricto.

Los tres paquetes se publican juntos y llevan la misma versión; la matriz de capacidades en docs/STATUS.md nombra la actual, y es la versión en npm. El cuerpo también está listado en el registro MCP como io.github.verax-ai/verax. Lo que esa versión lleva, lo que no, y la prueba que sostiene cada fila están en la matriz de capacidades en la parte superior de docs/STATUS.md.

Leer el libro mayor de vuelta sin nosotros

Un libro mayor que solo el servicio en ejecución del proveedor puede leer es evidencia de que un comprador alquila, no evidencia de que posee. verax verify lee un directorio de estado por sí solo — sin cuerpo escuchando, nada en la red — y declara cuatro cosas por separado, porque fallan por separado:

$ verax verify ./verax-state
ledger        ./verax-state
decisions     6
effects       4 (4 bound to a decision, 0 with none)
signatures    6 verify, 0 do not
chain         unbroken
verified with the key carried in these files
              verified against the key carried in the records themselves: this
              shows the files are internally consistent, not that the key was
              ever trusted. Pin a key you hold to check that.

VERIFIED

Ese último par de líneas es el punto. Verificar un libro mayor contra la clave que está a su lado prueba que los archivos concuerdan entre sí y nada más — cualquier cosa capaz de escribir el libro mayor podría escribir esa clave también. Pasa --key <public.pem> para verificar los registros de decisión contra una copia que tengas, y la respuesta dice a key you supplied en su lugar. Los efectos están firmados con una clave separada. Una fila self se verifica bajo la clave de efecto: --effect-key <public.pem> cuando la fijas, de otro modo una clave tomada de la primera fila self. Una fila same-org se verifica bajo la clave de testigo: --witness-key <public.pem> cuando la fijas, de otro modo una clave tomada de la primera fila same-org. Fijar --effect-key mientras una fila same-org está presente requiere --witness-key también, y fijar --witness-key mientras una fila self está presente requiere --effect-key también; de otro modo el resultado no está verificado. Cada una de esas líneas dice lo mismo: los archivos concuerdan entre sí, no que la clave fuera alguna vez tuya. Los checkpoints están firmados por la clave de testigo. Cada fila de checkpoint se verifica bajo una clave: --checkpoint-key <public.pem> cuando la fijas, de otro modo una clave tomada del archivo de checkpoint, con la misma nota de que el acuerdo no es confianza. La cola cuenta solo checkpoints cuyas firmas se verificaron. Alguien que pueda reescribir los archivos aún puede revertir ese archivo a un prefijo válido más antiguo junto con los registros posteriores; solo un checkpoint retenido en otro lugar detecta eso. --json imprime el mismo resultado para una canalización; el código de salida es 0 cuando verifica y 1 cuando no, y un directorio sin libro mayor nunca es un éxito silencioso.

Los registros son COSE_Sign1 con algoritmo -19 (Ed25519, RFC 9864), no el -8 polimórfico más antiguo (EdDSA). Algunas bibliotecas COSE aún no conocen -19: a partir de go-cose 1.3.0 y pycose 1.1.0 ambas lo rechazan, y el soporte se rastrea en go-cose#224 y pycose#126. verax verify no depende de ninguna de las dos bibliotecas.

Verificadores distintos de los nuestros

test-vectors/ es un conjunto congelado de libros mayores, cada uno con el veredicto y la etapa que un verificador debería informar. Dos personas han ejecutado el conjunto en vectors-v1 con verificadores propios y han publicado los resultados:

  • Tymofii Pidlisnyi (Agent Passport System), con un ejecutor en la suite de conformidad APS: una comparación parcial, etapa por etapa, en los 16 vectores, no un veredicto de libro mayor completo (ejecución).
  • Roberto Locatelli (cryptovalid-opencore), con verificadores de sala limpia escritos desde los borradores, los RFC y el README de vectores: con el checkpoint verificado bajo la clave de testigo, 16 de 16 veredictos y 15 de 16 primeras etapas fallidas. Una de esas coincidencias provino de una regla agregada después de leer el vector, como la propia ejecución declara (ejecución).

Una ejecución coincidente muestra que otro verificador lee estas codificaciones y llega al mismo veredicto en la misma etapa. No es una auditoría independiente del cuerpo.

Instalar

npm install -g @verax-ai/body
verax --help
verax doctor

En una cuenta donde cada proceso está elevado (el Administrador integrado, o EnableLUA=0), un comando desde un prefijo npm escribible por el usuario se deniega; usa la copia propiedad del administrador en %ProgramFiles%\verax-cli.

Node 22.6 o más reciente. El cuerpo habla MCP sobre Streamable HTTP en /mcp en VERAX_BIND (por defecto 127.0.0.1:8787) y necesita un emisor, una URL JWKS, una audiencia, un directorio de estado y un archivo de política antes de escuchar; verax doctor nombra lo que falta. Las variables y los pasos de ejecución están en packages/body/README.md.

Herramientas

La política decide cuáles de estas pueden llamar los alcances de un token; packages/proxy/policy/default.json deniega lo que no nombra.

HerramientaDescripción
memory.getLee un elemento de memoria detrás de la puerta, almacenado por inquilino.
memory.putEscribe un elemento de memoria detrás de la puerta, almacenado por inquilino.
audit.explainLee una decisión del libro de contabilidad firmado, con su cadena, sus firmas y sus hallazgos.
message.readLee la bandeja de entrada.
message.sendEscribe en la bandeja de salida; solo llega a los hosts que la política permite en la lista.
spendAutoriza un pago y lo registra, bajo un límite, una lista de beneficiarios y un límite diario de la política; se retiene para un operador cuando la política lo indica. El cuerpo no mueve dinero.

Qué hace el cuerpo más allá de la puerta

Cada línea a continuación es una fila en la matriz de capacidades en docs/STATUS.md, donde se indica contra una versión, con lo que no hace y la prueba que falla cuando deja de ser cierto.

  • Aprobación: una llamada retenida se aprueba con verax approve en esta máquina. En Windows, eso se ejecuta desde una cuenta de administrador separada. El panel de claves de acceso (verax operator, verax desktop) aún no se ha publicado. El id del operador aprobador se vincula al registro firmado mediante hash.
  • Testigo: verax witness firma filas de efectos desde un segundo proceso y escribe puntos de control duraderos; sin él, la clase de testigo permanece self.
  • Detención y revocación: verax halt convierte cada llamada posterior en una denegación firmada; un id de token revocado se rechaza antes de que se escriba cualquier registro.
  • Conciliación: verax reconcile compara los gastos registrados con una exportación de estado de cuenta de tarjeta y nombra las filas coincidentes, fantasma y autorizadas pero no pagadas.
  • Clave de inquilino: la memoria y la bandeja de entrada se almacenan bajo una clave derivada del emisor y sujeto del token; el id de otro inquilino se responde con una denegación firmada.
  • Límites: contadores de tasa y diarios, una negativa por disco bajo (HTTP 507) cuando una denegación no se pudo registrar, y una lista de permitidos de salida; los contadores que no se pueden leer fallan de forma segura.
  • Doctor y latido: verax doctor nombra lo que falta o está desactualizado antes de que la primera llamada lo descubra.

Vigilar el silencio (árbol no publicado)

El cuerpo en ejecución emite pulsos incluso en reposo (10 s por defecto; VERAX_HEARTBEAT_EVERY_MS, mínimo 1,000 ms). Las filas de inicio en starts.jsonl registran brechas desde el latido anterior; verax verify <stateDir> las resume sin conexión. Las filas de inicio no están firmadas en v1.

verax watch ./verax-state --max-silence 30s
verax watch ./verax-state --once
verax watch --url https://host/healthz --token-file ./audit.token --once
verax watch ./verax-state --on-silence exec --exec "node isolate.mjs"

Un latido ilegible, desactualizado o en un futuro lejano es silencio. Un vigilante local se detiene por defecto; la recuperación nunca lo reanuda. Un operador debe usar la ruta de reanudación existente. El vigilante remoto informa silencio y no puede detenerse de forma remota. Los tokens se leen solo de archivos; se requiere HTTPS excepto en loopback. Un comando exec se ejecuta una vez por episodio de silencio con VERAX_WATCH_REASON en su entorno, sin un shell. Cite ejecutables/argumentos que contengan espacios. --once sale con 0 en vivo, 3 en silencio o 2 en errores de uso. La vigilancia continua imprime una línea JSON por episodio de silencio y recuperación, sondeando en max-silence/3. Ejecútelo donde el operador elija; un vigilante en el mismo host comparte la confianza de ese host y no es evidencia independiente si tanto el libro de contabilidad como el vigilante desaparecen.

Conectar un cliente

El cuerpo escucha en http://127.0.0.1:8787/mcp por defecto. Una configuración de cliente se ve así; el token proviene de su emisor.

{
  "mcpServers": {
    "verax": {
      "url": "http://127.0.0.1:8787/mcp",
      "headers": { "Authorization": "Bearer <token from your issuer>" }
    }
  }
}

Estado

Lo que el árbol lleva y lo que permanece sin probar se indica, elemento por elemento, en docs/STATUS.md. Nada en este repositorio es una afirmación más allá de ese archivo, y un párrafo allí no es una publicación. El modelo de amenazas está en docs/THREAT_MODEL.md; cómo informar una vulnerabilidad está en SECURITY.md.

Qué más hay en el árbol

  • apps/panel es la pantalla de cuenta: la lista de registros, la caja negra y la vista de estado, leídas del libro de contabilidad firmado. Privada; no se publica. La sesión del panel usa el flujo de código; el token de acceso permanece en memoria y se descarta al actualizar. Vite puede aún adjuntar VERAX_DEV_TOKEN de .env.local a /api cuando la solicitud no tiene encabezado Authorization (cerebros MCP de escritorio y pruebas).
  • scripts/dev-issuer.mjs es solo para desarrollo; no es un servidor de autorización de producción. Sirve GET /authorize (PKCE S256) y POST /token, escribe un token en --out, y nunca imprime uno. Escucha en VERAX_DEV_ISSUER_PORT (predeterminado 8790). NODE_ENV=production sale.
  • scripts/demo-box.mjs es solo para desarrollo: un proceso que inicia el emisor de desarrollo y el cuerpo en loopback con un libro de contabilidad temporal, se acuña a sí mismo un token de corta duración a través del flujo de código del emisor, y habla MCP sobre stdio para un sandbox que no puede contener un token propio, como una verificación de compilación de un directorio. El cuerpo no se modifica por ello: cada llamada aún pasa la puerta y se registra, spend siempre se retiene, y no hay operador allí para aprobarlo. NODE_ENV=production sale. No es una implementación.

Desarrollo

npm ci
npm test            # guards, typecheck, build, unit and cost suites, panel
npm run pack:smoke  # pack the three packages and install them elsewhere

CI ejecuta la suite como un usuario no root en Linux y nuevamente en Windows, además de la verificación de rendimiento del proxy. Las versiones salen desde la pestaña Acciones: release.yml publica los tres paquetes con publicación confiable de npm y una atestación de procedencia, luego mcp-registry.yml actualiza el registro una vez que npm responde por la nueva versión. Ninguno se ejecuta al hacer push.

Probado en cada versión en las plataformas listadas en docs/PLATFORMS.md, cada fila vinculada a su ejecución de CI.

Licencia

Apache-2.0.