Verax

Verax: o corpo agente responsável. Portão, registro de decisão, recibo, reconciliação. Apache-2.0.

Documentação

Verax

O corpo que um agente consulta antes de agir.

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

Verax é um servidor MCP que fica entre um agente e suas ferramentas. Cada chamada de ferramenta passa por um portão de política e deixa um registro de decisão assinado antes que qualquer coisa seja executada; toda chamada que foi executada deixa uma linha de efeito que é reconciliada com seu registro depois. Uma recusa é registrada da mesma forma que uma aprovação. Uma chamada que a política não decide sozinha é retida até que um operador nesta máquina a aprove. O livro-razão permanece na máquina em que o corpo é executado, e o corpo só abre quando sua autorização está configurada: não há token padrão.

Quebre, e nós pagamos. USD 100 para cada relato válido de uma forma de a conta do agente ter uma chamada recusada permitida, executar uma chamada sem registro de decisão, ou alterar o código, chaves ou livro-razão do serviço. O orçamento é de USD 500 no total. Termos: SECURITY.md.

Por VERAX Teknoloji. Projetos irmãos: Conarium · Tugra · Cedulon. Os registros de decisão usam o formato de registro Cedulon.

Veja em execução

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

A gravação é a saída de uma execução em um terminal onde a pergunta de aprovação foi respondida y. Essa execução levou cerca de um segundo; é reproduzida lentamente aqui para que possa ser lida.

O que imprime, sem um terminal para responder à pergunta de aprovação:

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 ou mais recente, @verax-ai/body 0.2.1 ou posterior. O comando registra uma escrita e leitura de memória permitidas, uma recusa assinada de uma mensagem para um host fora da lista de políticas, e um pagamento retido para o operador nesta máquina (aprovado quando o terminal responde y).

--keep deixa o livro-razão temporário no disco. verax verify <dir> o lê de volta sem um corpo, como em Leia o livro-razão de volta sem nós.

As mesmas regras, animadas

Quatro episódios curtos mostram o mesmo portão, com personagens no lugar de um terminal. São cenários de exemplo: as cenas são desenhadas em three.js e as vozes são geradas com ElevenLabs.

Episódio 1, "$1.850": um pagamento é retido até que uma pessoa o aprove em um telefone, e mudar um centavo no registro quebra sua assinatura.

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

Episódio 2, "Sem regra, sem passagem": uma chamada sem regra é recusada, a mesma chamada sob um novo nome é recusada novamente, e ambas as recusas são assinadas.

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

Episódio 3, "A alavanca vermelha": um operador interrompe o corpo, toda chamada posterior é recusada e assinada, e uma chamada que já estava em execução não é cortada.

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

Episódio 4, "Quem aprovou?": um gasto retido espera por verax approve na máquina, o agente não pode aprová-lo, e o id do operador do aprovador vai para o registro.

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

Conecte seu agente

verax install e verax approve elevados executam uma cópia deste programa que apenas um administrador pode alterar; uma cópia que sua conta pode alterar é recusada. No Windows, um CLI elevado approve é a forma de aprovar até que o painel de passkey seja liberado. Ele deve ser executado a partir de uma conta de administrador separada, não desta conta elevada, porque um shell elevado do mesmo usuário herda as variáveis de ambiente e o perfil do PowerShell desse usuário, que o agente pode definir. Limpe NODE_OPTIONS nesse shell (Remove-Item Env:NODE_OPTIONS). Inicie o PowerShell da outra conta com -NoProfile (um shell elevado, caso contrário, executa seu $PROFILE, que sua conta pode alterar):

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

No Linux e macOS, com um Node de propriedade do root (o /usr/bin/node da distribuição, ou /opt/verax-node/<dir>/bin/node; o instalador imprime esses passos quando o Node a partir do qual foi iniciado pode ser alterado pela sua conta). Não inicie um comando elevado com 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

O comando instala @verax-ai/body do registro npm em um diretório de propriedade do administrador após verificações de assinatura, executa esse Node e mantém o livro-razão sob uma conta de serviço. No Windows, o token do agente é %ProgramData%\Verax\agent-token\<your SID>\agent.token (Administrators e SYSTEM têm controle total, seu SID pode ler o arquivo e ler-executar o diretório). No Linux e macOS, um processo filho executando como seu uid escreve ~/.verax/agent.token a partir de seu stdin. Ele imprime a linha do Claude Code que lê esse arquivo. Porta 8787 ocupada? verax install --port 8797. O Node deve ser o instalador para todos os usuários do nodejs.org no Windows; um Node que sua conta pode reescrever é recusado. No macOS, a correção extrai o tarball oficial como root em /opt/verax-node (root:wheel, não gravável por grupo ou outros). No Linux, o mesmo local, /opt/verax-node (root:root), que o SELinux rotula usr_t. Em sistemas SELinux, a instalação requer Node rotulado bin_t ou usr_t (o Node da distribuição é; um tarball sob /usr/local/lib não é) e imprime a correção de uma linha. O serviço então executa em unconfined_service_t. A conta de serviço e as permissões de arquivo são o limite.

Aprove uma chamada retida com verax approve. O painel de passkey (verax desktop) ainda não foi liberado. No Windows, execute a aprovação a partir de uma conta de administrador separada, não desta conta elevada, em um PowerShell -NoProfile após Remove-Item Env:NODE_OPTIONS: & "$env:ProgramFiles\verax-cli\verax.cmd" approve. Linux e macOS, nomeando o Node de propriedade do root: sudo /usr/bin/node /opt/verax-cli/lib/node_modules/@verax-ai/body/dist/cli.js approve ou sudo /opt/verax-node/<dir>/bin/node /opt/verax-cli/lib/node_modules/@verax-ai/body/dist/cli.js approve. Desinstale da mesma forma, com uninstall no lugar de approve.

Para experimentar em seu próprio usuário, que não é um limite:

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)"

O token pode ler e escrever memória através do portão; não pode aprovar. A política enviada recusa spend até que você adicione uma regra para ela; uma chamada que sua política retém espera por verax approve nesta máquina. Veja docs/THREAT_MODEL.md.

Com Conarium

@verax-ai/body 0.2.2 e posterior aceita --with-conarium. 0.2.1 não carrega a flag. A flag tem npx baixar @conarium-ai/core do npm e executá-lo como um processo filho; isso precisa de rede.

Conarium mascara as linhas, e sua política de exemplo nega sua tabela public.secrets. Verax coloca cada chamada através do mesmo portão que suas próprias ferramentas, mantém um registro assinado e um hash da resposta, e recusa uma ferramenta downstream que a política não nomeia antes que o filho veja a chamada. Quando Conarium responde com um erro, o corpo diz ao chamador que ele o fez, não o que ele disse.

O que imprime, sem um terminal para responder à pergunta de aprovação:

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).

O que é enviado

PacoteO que é
@verax-ai/bodyO servidor MCP e o comando verax: serve, install, uninstall, init, doctor, approve, operator, reconcile, witness, halt, resume, unlock (desktop ainda não foi liberado).
@verax-ai/proxyO proxy de decisão sobre o qual o corpo é construído: política, registros assinados, livro-razão, explain, reconciliar.
@verax-ai/inventoryO documento de roster que um corpo serve e as listas do painel, com seu parser estrito.

Os três pacotes são publicados juntos e carregam a mesma versão; a matriz de capacidades em docs/STATUS.md nomeia a atual, e é a versão no npm. O corpo também está listado no registro MCP como io.github.verax-ai/verax. O que essa versão carrega, o que não carrega, e o teste que sustenta cada linha estão na matriz de capacidades no topo de docs/STATUS.md.

Leia o livro-razão de volta sem nós

Um livro-razão que apenas o serviço em execução do fornecedor pode ler é evidência de que um comprador aluga, não evidência de que ele possui. verax verify lê um diretório de estado por conta própria — sem corpo ouvindo, nada na rede — e declara quatro coisas separadamente, porque elas falham separadamente:

$ 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

Esse último par de linhas é o ponto. Verificar um livro-razão contra a chave ao lado dele prova que os arquivos concordam entre si e nada mais — qualquer coisa capaz de escrever o livro-razão poderia escrever essa chave também. Passe --key <public.pem> para verificar registros de decisão contra uma cópia que você possui, e a resposta diz a key you supplied em vez disso. Efeitos são assinados com uma chave separada. Uma linha self é verificada sob a chave de efeito: --effect-key <public.pem> quando você a fixa, caso contrário, uma chave tirada da primeira linha self. Uma linha same-org é verificada sob a chave de testemunha: --witness-key <public.pem> quando você a fixa, caso contrário, uma chave tirada da primeira linha same-org. Fixar --effect-key enquanto uma linha same-org está presente requer --witness-key também, e fixar --witness-key enquanto uma linha self está presente requer --effect-key também; caso contrário, o resultado não é verificado. Cada uma dessas linhas diz a mesma coisa: os arquivos concordam entre si, não que a chave já foi sua. Checkpoints são assinados pela chave de testemunha. Cada linha de checkpoint é verificada sob uma chave: --checkpoint-key <public.pem> quando você a fixa, caso contrário, uma chave tirada do arquivo de checkpoint, com a mesma nota de que concordância não é confiança. A cauda conta apenas checkpoints cujas assinaturas foram verificadas. Alguém que pode reescrever os arquivos ainda pode reverter esse arquivo para um prefixo válido mais antigo junto com os registros depois dele; apenas um checkpoint mantido em outro lugar detecta isso. --json imprime o mesmo resultado para um pipeline; o código de saída é 0 quando verifica e 1 quando não, e um diretório sem livro-razão nunca é sucesso silencioso.

Registros são COSE_Sign1 com algoritmo -19 (Ed25519, RFC 9864), não o antigo -8 polimórfico (EdDSA). Algumas bibliotecas COSE não conhecem -19 ainda: a partir de go-cose 1.3.0 e pycose 1.1.0, ambas o rejeitam, e o suporte é rastreado em go-cose#224 e pycose#126. verax verify não depende de nenhuma das bibliotecas.

Verificadores além dos nossos

test-vectors/ é um conjunto congelado de livros-razão, cada um com o veredito e o estágio que um verificador deve relatar. Duas pessoas executaram o conjunto em vectors-v1 com verificadores próprios e publicaram os resultados:

  • Tymofii Pidlisnyi (Agent Passport System), com um executor no conjunto de conformidade APS: uma comparação parcial, estágio por estágio, em todos os 16 vetores, não um veredito de livro-razão inteiro (execução).
  • Roberto Locatelli (cryptovalid-opencore), com verificadores de sala limpa escritos a partir dos rascunhos, das RFCs e do README do vetor: com o checkpoint verificado sob a chave de testemunha, 16 de 16 vereditos e 15 de 16 primeiros estágios com falha. Uma dessas correspondências veio de uma regra adicionada após a leitura do vetor, como a própria execução afirma (execução).

Uma execução correspondente mostra que outro verificador lê essas codificações e alcança o mesmo veredito no mesmo estágio. Não é uma auditoria independente do corpo.

Instalação

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

Em uma conta onde todo processo é elevado (o Administrador integrado, ou EnableLUA=0), um comando de um prefixo npm gravável pelo usuário é recusado; use a cópia de propriedade do administrador em %ProgramFiles%\verax-cli.

Node 22.6 ou mais recente. O corpo fala MCP sobre Streamable HTTP em /mcp na VERAX_BIND (padrão 127.0.0.1:8787) e precisa de um emissor, uma URL JWKS, um público, um diretório de estado e um arquivo de política antes de ouvir; verax doctor nomeia o que está faltando. As variáveis e os passos de execução estão em packages/body/README.md.

Ferramentas

A política decide quais destas os escopos de um token podem chamar; packages/proxy/policy/default.json nega o que não nomeia.

FerramentaDescrição
memory.getLê um item de memória atrás do portão, armazenado por locatário.
memory.putGrava um item de memória atrás do portão, armazenado por locatário.
audit.explainLê uma decisão de volta do livro-razão assinado, com sua cadeia, suas assinaturas e suas conclusões.
message.readLê a caixa de entrada.
message.sendGrava na caixa de saída; alcança apenas hosts na lista de permissões da política.
spendAutoriza um pagamento e o registra, sob um limite, uma lista de beneficiários e um limite diário da política; retido para um operador quando a política assim determina. O corpo não movimenta dinheiro.

O que o corpo faz além do portão

Cada linha abaixo é uma linha na matriz de capacidades em docs/STATUS.md, onde é declarada contra uma versão, com o que ela não faz e o teste que falha quando deixa de ser verdadeira.

  • Aprovação: uma chamada retida é aprovada com verax approve nesta máquina. No Windows, isso é executado a partir de uma conta de administrador separada. O painel de chave de acesso (verax operator, verax desktop) ainda não foi liberado. O ID do operador aprovador é vinculado ao registro assinado por hash.
  • Testemunha: verax witness assina linhas de efeito a partir de um segundo processo e grava pontos de verificação duráveis; sem ele, a classe de testemunha permanece self.
  • Parada e revogação: verax halt transforma toda chamada adicional em uma negação assinada; um ID de token revogado é recusado antes que qualquer registro seja gravado.
  • Reconciliação: verax reconcile compara gastos registrados com uma exportação de extrato de cartão e nomeia as linhas correspondentes, fantasmas e autorizadas-mas-não-pagas.
  • Chave do locatário: memória e caixa de entrada são armazenadas sob uma chave derivada do emissor e assunto do token; o ID de outro locatário é respondido com uma negação assinada.
  • Limites: contadores de taxa e diários, uma recusa por disco cheio (HTTP 507) quando uma negação não pôde ser registrada, e uma lista de permissões de saída; contadores que não podem ser lidos falham de forma segura.
  • Doctor e heartbeat: verax doctor nomeia o que está ausente ou desatualizado antes que a primeira chamada descubra.

Observe o silêncio (árvore não lançada)

O corpo em execução pulsa mesmo quando ocioso (10 s por padrão; VERAX_HEARTBEAT_EVERY_MS, mínimo 1.000 ms). Linhas de início em starts.jsonl registram lacunas do batimento anterior; verax verify <stateDir> resume elas offline. Linhas de início não são assinadas na 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"

Um batimento ilegível, desatualizado ou muito no futuro é silêncio. Uma observação local para por padrão; a recuperação nunca a retoma. Um operador deve usar o caminho de retomada existente. Observação remota relata silêncio e não pode parar remotamente. Tokens são lidos apenas de arquivos; HTTPS é obrigatório, exceto em loopback. Um comando exec é executado uma vez por episódio de silêncio com VERAX_WATCH_REASON em seu ambiente, sem shell. Cite executável/argumentos contendo espaços. --once sai com 0 ao vivo, 3 silencioso ou 2 em erros de uso. Observação contínua imprime uma linha JSON por episódio de silêncio e recuperação, sondando em max-silence/3. Execute-o onde o operador escolher; um observador no mesmo host compartilha a confiança desse host e não é evidência independente se tanto o livro-razão quanto o observador desaparecerem.

Conecte um cliente

O corpo escuta em http://127.0.0.1:8787/mcp por padrão. Uma configuração de cliente se parece com isto; o token vem do seu emissor.

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

Status

O que a árvore carrega e o que permanece não comprovado é declarado, item por item, em docs/STATUS.md. Nada neste repositório é uma afirmação além desse arquivo, e um parágrafo lá não é um lançamento. O modelo de ameaças está em docs/THREAT_MODEL.md; como relatar uma vulnerabilidade está em SECURITY.md.

O que mais está na árvore

  • apps/panel é a tela de conta: a lista de registros, a caixa preta e a visualização de status, lidas do livro-razão assinado. Privada; não é publicada. A sessão do painel usa o fluxo de código; o token de acesso permanece na memória e é descartado na atualização. O Vite pode ainda anexar VERAX_DEV_TOKEN de .env.local a /api quando a solicitação não tem cabeçalho Authorization (cérebros MCP de desktop e testes).
  • scripts/dev-issuer.mjs é apenas para desenvolvimento; não é um servidor de autorização de produção. Ele atende GET /authorize (PKCE S256) e POST /token, grava um token em --out e nunca imprime um. Ele escuta em VERAX_DEV_ISSUER_PORT (padrão 8790). NODE_ENV=production sai.
  • scripts/demo-box.mjs é apenas para desenvolvimento: um processo que inicia o emissor de desenvolvimento e o corpo em loopback com um livro-razão temporário, cunha para si um token de curta duração através do fluxo de código do emissor e fala MCP via stdio para um sandbox que não pode manter um token próprio, como uma verificação de build de um diretório. O corpo não é alterado por ele: toda chamada ainda passa pelo portão e é registrada, spend é sempre retido, e nenhum operador está lá para aprová-lo. NODE_ENV=production sai. Não é uma implantação.

Desenvolvendo

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

O CI executa a suíte como um usuário não root no Linux e novamente no Windows, além da verificação de desempenho do proxy. Lançamentos saem da aba Actions: release.yml publica os três pacotes com publicação confiável do npm e uma atestação de proveniência, então mcp-registry.yml atualiza o registro uma vez que o npm responde pela nova versão. Nenhum é executado em push.

Testado em cada lançamento nas plataformas listadas em docs/PLATFORMS.md, cada linha vinculada à sua execução de CI.

Licença

Apache-2.0.