Torii
Torii é uma fronteira MCP local que permite a agentes executar ferramentas de infraestrutura sob uma política explícita e auditável.
Cliente MCP
|
| tool: kubectl
| target: mpce_dev
| args: ["get", "pods"]
v
Torii -> target -> Jasper -> sessão isolada -> processo filho
O projeto separa dois mundos:
- humanos operam
aws,kubectl,azegclouddiretamente; - agentes recebem tools MCP fornecidas pelo Torii;
- Jasper decide o que pode atravessar;
- o executável real continua responsável por validar sua gramática e permissões remotas.
O que o Torii garante
- tudo começa negado;
- um
denyexplícito tem prioridade sobre qualquer permissão; - argumentos permanecem estruturados e nunca passam por shell;
- políticas são avaliadas antes da leitura de credenciais;
- sessões coletadas pelo Torii são aplicadas somente ao processo filho;
- cada provider instalado vira exatamente uma tool MCP;
- targets são aliases cadastrados pelo humano, nunca contexts livres fornecidos pelo agente;
- aliases target-aware começam inativos e exigem um lease humano temporário antes de grants, ambiente ou autenticação;
- aliases
aws_profilefixam profile e conta esperada fora do MCP e conferem a conta antes da execução; - decisões e exit codes são auditados sem registrar credenciais.
O que o Torii não é
Torii não é um novo AWS CLI, um parser completo de Kubernetes, um daemon multiusuário ou um catálogo de todas as operações de nuvem. Também não oferece ao agente tools para editar políticas, instalar providers, renovar credenciais ou desligar o servidor.
Estado da implementação
A estratégia de autenticação environment está implementada e atende sessões temporárias AWS. inherited está implementada para providers que usam o ambiente ou credential store já isolado pelo operador; o modo aws_profile a combina com alias humano, remoção de overrides e verificação STS de conta. Os nomes session_command e credential_file fazem parte do schema, mas são recusados em runtime até que providers reais justifiquem suas implementações.
Para colocar o servidor em funcionamento, siga Instalação e Primeiros passos. Para entender as garantias antes de operar em um ambiente sensível, leia o Modelo de segurança.
Instalação
Instalação rápida
Linux x86_64:
curl -fsSL https://raw.githubusercontent.com/torii-mcp/torii/main/install.sh | sh
Windows x86_64:
irm https://raw.githubusercontent.com/torii-mcp/torii/main/install.ps1 | iex
Os dois scripts baixam a última release, conferem o SHA-256 publicado antes de extrair e instalam o binário num diretório do usuário — nada exige administrador ou sudo. Sem um verificador de hash disponível, a instalação para em vez de prosseguir sem conferir.
| Linux | Windows | |
|---|---|---|
| destino padrão | ~/.local/bin | %LOCALAPPDATA%\Programs\Torii |
| mudar destino | --dir <caminho> ou TORII_INSTALL_DIR | -InstallDir <caminho> |
| versão fixa | --version v0.2.0 ou TORII_VERSION | -Version v0.2.0 |
| PATH | só com --add-to-path | automático, salvo -NoPathUpdate |
No Linux, o script não mexe no seu shell rc por padrão: ele imprime a linha do export PATH para você colar. Com --add-to-path, escreve um bloco marcado no rc do seu shell (.bashrc, .zshrc, config.fish ou .profile) e não duplica em execuções seguintes. No Windows, o destino entra no PATH do usuário; abra um novo terminal para enxergá-lo.
Para passar opções através do pipe, use sh -s --:
curl -fsSL https://raw.githubusercontent.com/torii-mcp/torii/main/install.sh | sh -s -- --add-to-path
Executar um script vindo da rede é um ato de confiança. Se preferir revisar antes — o que é razoável para uma ferramenta que existe para restringir execução — baixe, leia e só então rode:
curl -fsSLO https://raw.githubusercontent.com/torii-mcp/torii/main/install.sh
less install.sh
sh install.sh
Reinstalar sobre uma versão anterior é o caminho normal de atualização: o script troca o binário e informa a versão anterior e a nova. Depois de instalado, torii self upgrade faz o mesmo sem baixar script nenhum.
Binários oficiais
Os releases do Torii publicam dois pacotes para cada tag:
| Plataforma | Pacote |
|---|---|
| Windows x86_64 | torii-vX.Y.Z-windows-x86_64.zip |
| Linux x86_64 | torii-vX.Y.Z-linux-x86_64.tar.gz |
Cada pacote acompanha um arquivo .sha256. Extraia o executável e coloque-o em um diretório do PATH ou use seu caminho absoluto na configuração do cliente MCP.
Para conferir o download à mão:
sha256sum -c torii-v0.2.0-linux-x86_64.tar.gz.sha256
(Get-FileHash torii-v0.2.0-windows-x86_64.zip -Algorithm SHA256).Hash
O checksum é publicado junto do pacote, no mesmo release. Ele detecta download corrompido ou truncado; não é assinatura criptográfica, e o roadmap registra a assinatura de artefatos como fora do escopo atual.
Trocar de versão
torii self upgrade --check # só informa se existe versão nova
torii self upgrade # baixa, confere o SHA-256 e troca o binário
O comando resolve a última release para a sua plataforma, confere o checksum e substitui o executável em execução. Configuração, políticas, targets, grants e credenciais não são tocados. No Windows, o binário anterior fica como torii.exe.old enquanto o processo atual o mantém aberto; a atualização seguinte o remove, e o comando avisa quando isso acontece.
Reinicie os clientes de agente depois de atualizar: um cliente MCP em execução continua com o binário anterior carregado.
Pré-requisitos
- Rust estável compatível com as dependências do projeto;
- o executável de cada provider no
PATH, comoawsoukubectl; - acesso a uma interface gráfica para aprovação e coleta de credenciais, ou
TORII_NO_GUI=1para execução estritamente headless; - mdBook 0.5 ou mais recente para construir esta documentação.
Compilar o Torii
Na raiz do repositório:
cargo build --release
O binário será criado em target/release/torii.exe no Windows ou target/release/torii em sistemas Unix.
As releases são produzidas automaticamente pelo GitHub Actions quando uma tag vX.Y.Z é enviada. O Windows usa o target MSVC e o Linux usa x86_64-unknown-linux-gnu.
Particularidade do Windows GNU
eframe, usado pelas janelas locais, exige um MinGW-w64 completo durante o link. Se aparecer error calling dlltool ou ausência de as.exe, adicione ao PATH o diretório bin de uma distribuição MinGW-w64 completa antes de executar cargo build ou cargo test.
Isso é uma exigência de build, não uma configuração do Torii.
Instalar mdBook
Binários prontos estão disponíveis nos releases do projeto mdBook. Quem já possui Cargo também pode instalar a ferramenta:
cargo install mdbook --version 0.5.4 --locked
mdbook build docs
O HTML gerado fica em docs/book/ e não deve ser versionado.
Diretório de configuração
Por padrão, Torii usa:
~/.config/torii
Para desenvolvimento ou testes, isole a configuração:
$env:TORII_CONFIG_DIR = "$PWD/.torii-dev"
O Torii não lê AWSGATE_CONFIG_DIR e não migra configuração do AWS Gate automaticamente.
Primeiros passos
Este fluxo usa configuração isolada e um pacote local do repositório para permitir revisão antes da execução.
1. Inicializar a raiz
$env:TORII_CONFIG_DIR = "$PWD/.torii-dev"
cargo run -- init
init cria apenas settings.yaml e a estrutura base. Providers são instalados explicitamente.
2. Instalar providers
Durante o desenvolvimento local:
cargo run -- provider install ./examples/providers/aws
cargo run -- provider install ./examples/providers/kubectl
cargo run -- provider list
Em uma distribuição configurada com o catálogo canônico, use apenas provider install aws ou pesquise com provider search.
Após a instalação, ambos os rules.yaml estão vazios. Nenhuma operação do agente atravessa por padrão.
3. Aplicar um setup opcional
cargo run -- provider setup aws readonly
cargo run -- provider setup kubectl readonly
O setup aplica a política curada somente se rules ainda estiver vazio. Revise a política AWS conforme sua classificação de dados.
4. Criar target Kubernetes
cargo run -- target add kubectl meu_dev --context meu-context-real --provider aws
cargo run -- target activate kubectl meu_dev --for 30
O alias é publicado no schema depois de reiniciar o MCP, mas começa inativo. target activate concede o lease humano necessário antes de grants, ambiente e autenticação. Sem --add, ele substitui qualquer outro alias ativo da tool.
5. Preparar uma sessão AWS
cargo run -- reauth aws
Torii valida a candidata com aws sts get-caller-identity antes de substituir a sessão anterior.
6. Iniciar o MCP
cargo run
Normalmente o cliente MCP inicia esse processo. Em headless, TORII_NO_GUI=1 nega chamadas não resolvidas e cancela coleta de autenticação com segurança.
Conectar um cliente MCP
O cliente é responsável por iniciar e encerrar o Torii. O transporte é stdio; fechar stdin ou terminar o processo encerra a sessão.
Configuração genérica:
{
"mcpServers": {
"torii": {
"command": "C:/tools/torii.exe",
"env": {
"TORII_CONFIG_DIR": "C:/Users/voce/.config/torii"
}
}
}
}
Em Unix, use o caminho correspondente:
{
"mcpServers": {
"torii": {
"command": "/home/voce/bin/torii"
}
}
}
Nem todo cliente usa mcpServers: o opencode declara servidores em mcp, com o comando em vetor e o ambiente em environment, e o Copilot no VS Code usa servers. Em vez de acertar isso à mão, use torii agent install <agent>, que escreve o formato de cada cliente — veja Integrar agentes.
Descoberta de tools
No startup, Torii carrega os subdiretórios de providers/. Cada provider.yaml válido produz uma tool. Alterações em providers exigem reiniciar o servidor para reconstruir o registry.
O conjunto inicial costuma ser:
aws
kubectl
Quando instalado, o pacote de aliases AWS acrescenta aws_profile. Seus targets anunciados são aliases humanos; profile e conta não aparecem para o cliente MCP. Todo alias configurado continua no schema, mesmo antes de um humano conceder seu lease temporário.
Além de uma tool por provider, o Torii publica torii_policy, uma consulta somente de leitura das regras accept e deny ativas. Não existem tools MCP de kill, reauth, instalação ou edição de política.
Integridade do stdout
Stdout pertence ao protocolo. Não envolva o Torii com scripts que imprimam banners, mensagens de login ou diagnósticos no mesmo stream. Mensagens humanas devem ir para stderr; a auditoria fica em torii.log.
Chamada
Providers simples usam:
{
"args": ["s3", "ls"]
}
Providers target-aware exigem o alias anunciado no schema:
{
"target": "mpce_dev",
"args": ["get", "pods", "-n", "agente-rm"]
}
Não envie uma linha inteira em um campo command e não junte argumentos que deveriam ser itens separados. Veja a API MCP para respostas e erros.
Descobrir a política antes de executar
O agente deve consultar torii_policy antes de escolher uma operação, em especial quando a allowlist não é conhecida:
{
"provider": "aws"
}
Para uma tool com target, inclua o alias:
{
"provider": "kubectl",
"target": "mpce_dev"
}
A consulta não executa o provider nem lê sessão ou lease. Regras fora de accept e deny continuam em default deny até uma aprovação humana ou grant temporário.
Se um alias target-aware estiver inativo, o Torii pede a decisão humana sobre o binding antes de grants, ambiente e autenticação. Em headless, a chamada é negada. O agente não deve tentar ativar, limpar ou substituir aliases; aguarda a decisão humana. Se o humano mantiver mais de um alias ativo, o agente ainda pode escolher qualquer um deles nas operações permitidas.
Se uma chamada aws_profile autorizada informar que a identidade não corresponde ao alias, peça que o humano autentique o profile configurado pelo AWS CLI e então repita a mesma chamada. Não tente enviar --profile, --region ou escolher outro target.
Referência rápida
Uma página para consultar durante a operação. Cada item aponta para o capítulo que explica
o porquê. Exemplos em PowerShell; em shells POSIX troque $env:VAR = "valor" por
export VAR=valor.
Modelo mental em cinco linhas
agente → MCP stdio → Torii → lease do target → Jasper → sessão isolada → CLI real
- o humano continua usando
aws,kubectleazdireto no terminal; - o agente recebe uma tool por provider instalado, nunca uma tool por operação;
- tudo começa negado: sem
accept, grant ou aprovação humana, não passa; - um
denyexplícito vence accept, grant e aprovação humana; - alias target-aware nasce inativo: precisa de um lease humano temporário.
Detalhes em Modelo mental e Modelo de segurança.
Instalar
Linux x86_64:
curl -fsSL https://raw.githubusercontent.com/torii-mcp/torii/main/install.sh | sh
# opções pelo pipe: sh -s -- --add-to-path --dir ~/bin --version v0.2.0
Windows x86_64:
irm https://raw.githubusercontent.com/torii-mcp/torii/main/install.ps1 | iex
# opções: .\install.ps1 -InstallDir D:\tools\torii -NoPathUpdate -Version v0.2.0
Os dois conferem o SHA-256 publicado antes de extrair e instalam sem administrador. No
Windows o destino entra no PATH do usuário; no Linux, só com --add-to-path. Reabra o
terminal depois.
Apontar a raiz e trocar de versão
torii --version # confirma o binário
torii init # cria a raiz e settings.yaml
torii config-dir # mostra a raiz efetiva
torii self upgrade # troca o binário pela última release; --check só informa
Upgrade, não update: trocar a versão de algo instalado é sempre upgrade — do binário
(self upgrade) ou de um pacote (provider upgrade). Não existe update no Torii, porque
não há índice local para sincronizar.
| Variável | Efeito |
|---|---|
TORII_CONFIG_DIR | substitui a raiz inteira (default ~/.config/torii) |
TORII_NO_GUI=1 | headless: chamada não resolvida é negada, coleta é cancelada |
TORII_PROVIDER_CATALOG | usa outro index.yaml (local ou HTTPS) no lugar do catálogo oficial |
Conectar um cliente MCP
torii agent list # adapters implementados
torii agent install claude --hook # com hook: codex | claude | gemini | cursor | antigravity
torii agent install opencode # sem hook: opencode | copilot | copilot-cli
torii agent install pi --yes # pi depende de uma extensão MCP instalada por você
torii agent status claude
torii agent uninstall claude --hook # remove tudo; sem --hook remove só o MCP
Reinicie o cliente depois de instalar ou remover. O --hook bloqueia chamadas diretas aos
executáveis dos providers instalados: reduz bypass acidental, não substitui sandbox do
sistema operacional. Configuração manual em Conectar um cliente MCP e
Integrar agentes.
Configurar um provider
torii provider search # consulta o catálogo
torii provider search kubernetes
torii provider install aws # nome do catálogo
torii provider install ./examples/providers/az # diretório, .zip, .tar.gz ou URL HTTPS
torii provider setup aws readonly # aplica política de exemplo read-only
torii provider list # tool, nome, executável, versão e origem
torii provider upgrade aws # só arquivos do pacote; nunca rules, .env ou estado
Todo pacote instala rules.yaml vazio: nada atravessa até você escrever a política.
setup recusa sobrescrever uma política que já tenha accepts ou denies. Ver
Operar providers e sessões e
Pacotes e catálogo.
Ajustar permissões (política)
torii policy show aws # imprime a política ativa e seu caminho
torii policy edit aws # abre no $EDITOR, valida antes de aplicar
torii policy edit kubectl dev # política só daquele alias
torii policy edit kubectl dev --create # cria a política do alias, que substitui a compartilhada
O arquivo é providers/<provider>/rules.yaml; um targets/<alias>/rules.yaml substitui a
política compartilhada naquele alias. policy edit edita uma cópia: YAML malformado ou regex
inválido nunca chega ao arquivo vivo, e o rascunho recusado é preservado.
version: "1"
deny:
- "ecs execute-command" # prefixo de tokens
- "/(?i)\\bdrop\\s+table\\b/i" # regex sobre o argv inteiro
accept:
- "ec2 describe-instances"
- "s3 ls"
| Forma | Como casa |
|---|---|
"ec2 describe-instances" | prefixo de tokens; ec2 describe não casa parcialmente |
"/padrão/flags" | regex em qualquer posição do argv; flags i, m, s, x |
forbidden_args | argumento negado em qualquer posição, antes de qualquer regra |
ignore_args | normaliza o argv só para avaliar; nunca altera o comando executado |
ec2 describe-instances --region sa-east-1 casa com o accept acima. Regex inválido falha
fechado (erro, nunca allow silencioso). rules.yaml é relido em cada chamada — não precisa
reiniciar o MCP. Ver Escrever políticas e
Schema de provider.
Para uma aprovação pontual, deixe a chamada cair em unresolved: a janela local permite negar, permitir uma vez ou conceder um grant temporário. O agente nunca edita política.
Targets e leases (tools target-aware)
# Kubernetes: alias → context do kubeconfig, autenticado por outro provider
torii target add kubectl dev --context mdb-k8s-dev-ia --provider aws --expect 111122223333
# AWS por profile humano: alias → profile + conta esperada
torii target add aws_profile producao --profile empresa-producao --account-id 111122223333 --region sa-east-1
torii target list kubectl # aliases e bindings (só no control plane humano)
torii target show kubectl dev
torii target activate kubectl dev --for 30 # concede o lease; substitui os ativos da tool
torii target status kubectl # leases vivos e expirações
torii target clear kubectl # revoga todos os leases da tool
torii target remove kubectl dev --force
| Fato | Consequência |
|---|---|
| criar alias não ativa | o alias aparece no schema MCP, mas a chamada exige lease |
--for aceita 1 a 1.440 min | sem --for, usa default_target_minutes (15) |
| ativação normal substitui | todos os outros aliases ativos daquela tool são desativados |
--add acumula | o agente pode escolher qualquer alias ativo em operação permitida |
clear só revoga leases | não apaga target, rules, grants, .env, cache nem mata processos |
mudou target.yaml | o digest do binding invalida o lease imediatamente |
Criar ou remover alias muda o enum do schema e exige reiniciar o MCP; ativar, limpar ou expirar não. Ver Configurar Kubernetes e AWS por profile e aliases.
Autenticar e reautenticar
torii reauth aws # provider simples, autenticação gerenciada
torii reauth kubectl dev # delega ao provider de identidade, no escopo do target
aws sso login --profile empresa-producao # aws_profile: fluxo nativo, fora do Torii
| Estratégia | Reauth pelo Torii |
|---|---|
environment | sim: janela coleta os campos e valida antes de substituir a sessão |
inherited sem validator | não há material renovável; a sessão do ambiente é usada como está |
inherited com validator (SSO/profile) | não: autentique pelo fluxo nativo e repita a chamada |
aws_profile | não troca sessão: autentique o profile configurado e repita o mesmo alias |
Uma chamada já autorizada abre a janela de autenticação sozinha quando a sessão gerenciada não está disponível. Não existe tool MCP de reauth. Ver Sessões de autenticação.
O que o agente vê
{ "name": "aws", "arguments": { "args": ["s3", "ls"] } }
{ "name": "kubectl", "arguments": { "target": "dev", "args": ["get", "pods"] } }
{ "name": "torii_policy", "arguments": { "provider": "kubectl", "target": "dev" } }
torii_policy é somente leitura: devolve accept, deny, minimum_accept_tokens e
ignored_accept, sem tocar credenciais, grants ou leases. O agente não recebe tools de
reauth, kill, instalação, edição de política ou ativação de target. Ver
API MCP.
Ler a decisão e a auditoria
A resposta traz decision.result, decision.source e, quando executou, execution com
exit_code, stdout, stderr e truncated. O log fica em <raiz>/torii.log:
epoch | escopo | evento | regra-curta | detalhe
1784000000 | aws | allowed-by-rules | ec2 describe-instances
1784000003 | kubectl/dev | ran | get pods | exit=0
| Evento | Leitura |
|---|---|
allowed-by-rules / allowed-by-grant | passou por accept ou por grant vivo |
denied-explicit | casou um deny; nada mais foi consultado |
override-once / override-timed | humano aprovou na janela, uma vez ou por tempo |
target-access-* | pedido, substituição, adição, revogação ou perda de lease |
identity-mismatch | conta ativa diferente da esperada; comando não executou |
session-* | estado da sessão do escopo de credencial |
Sem credenciais, clipboard ou saída completa. Escrita best-effort: é observabilidade local, não ledger de compliance. Ver Auditoria.
Quando reiniciar o servidor MCP
| Mudança | Reiniciar? |
|---|---|
editar rules.yaml | não |
| ativar, limpar ou expirar lease | não |
| conceder grant temporário | não |
| instalar, atualizar ou remover provider | sim |
| criar ou remover target | sim |
alterar PATH ou TORII_CONFIG_DIR | sim |
Diagnóstico rápido
| Sintoma | Primeira verificação |
|---|---|
no providers installed | torii config-dir e torii provider list; init não instala providers |
rules file not found | o provider não tem rules.yaml; não existe fallback permissivo |
could not find the executable ... in PATH | where <cli> no mesmo terminal e reinicie o cliente MCP |
| negado sem abrir janela | casou um deny, ou TORII_NO_GUI está setado |
| alias inativo / negado em headless | torii target status <tool> e target activate |
| muitos aliases ativos | target status, depois target clear ou ativar sem --add |
conta divergente em aws_profile | autentique o profile e confira torii target show |
execution.truncated: true | saída acima de max_output_bytes em settings.yaml |
Casos completos em Solução de problemas.
Não faça
- não peça ao agente para trocar context, profile, conta ou região: isso é control plane humano;
- não deixe vários aliases ativos sem necessidade;
- não escreva política permissiva contando com RBAC/IAM, nem o contrário: as duas camadas somam;
- não versione nem sincronize a raiz de configuração; ela contém sessão e credenciais;
- não aceite operações que devolvem segredos, tokens ou credenciais em política read-only;
- não trate o hook de agente como isolamento real de processo.
Modelo mental
A menor descrição correta do Torii é:
servidor MCP local
+ registry pequeno de providers e targets
+ Jasper
+ controle humano local
+ sessões isoladas por escopo
+ runner sem shell
Três fronteiras
Data plane do agente
O agente lista tools e chama um provider com args: string[]. Em uma tool target-aware, escolhe apenas um alias anunciado pelo schema. Todos os aliases configurados são anunciados, mas só os que possuem lease humano válido podem atravessar para grants, ambiente e autenticação. Ele não cadastra ou ativa targets, não fornece contexts reais, não conhece credenciais e não controla configuração ou lifecycle.
Control plane humano
O humano edita YAML, cadastra aliases, aprova chamadas não resolvidas e renova sessões. Os subcomandos locais existem apenas para esse controle.
Autoridade externa
Mesmo quando Jasper permite uma tentativa, AWS IAM, Kubernetes RBAC ou a autoridade equivalente ainda decide se a identidade pode realizar a operação.
Jasper: o agente pode tentar?
Cloud/cluster: esta identidade pode realizar?
Escopos
Providers simples, como aws, isolam política e sessão na raiz do provider. Providers target-aware, como kubectl, compartilham o mecanismo e isolam política, grants e ambiente por alias:
kubectl/mpce_dev
kubectl/cliente_hml
O alias é identidade de configuração, auditoria e grants; o context real permanece sob controle humano. O conjunto de leases é exceção deliberada: fica no escopo do provider para substituir ou adicionar aliases de forma atômica.
aws_profile usa o mesmo conceito de alias, mas o binding é profile local mais conta esperada. Esses valores permanecem no control plane; para o agente, producao é apenas o alias anunciado.
Um alias configurado não é automaticamente utilizável. O humano o ativa por um lease temporário; a ativação padrão substitui todos os aliases ativos da mesma tool. Na janela aberta por uma chamada, quando Adicionar criar múltiplos ativos, o alerta fica junto às ações e o humano mantém o botão pressionado por 1 segundo para confirmar que o agente poderá escolher qualquer alias ativo enquanto o lease durar. No CLI, target activate --add explicita a mesma escolha.
Modelo de segurança
O Torii reduz a superfície de execução disponível ao agente. Ele não transforma um CLI ou credencial de alto privilégio em algo seguro por si só; política local e privilégios remotos precisam ser configurados em conjunto.
Invariantes
- Default deny. Ausência de regra ou grant não significa permissão.
- Deny prioritário. Um deny compatível encerra a avaliação antes de qualquer aprovação.
- Autorização antes de autenticação.
.env, credenciais e cache não são lidos no caminho negado. - Sem shell. O Torii nunca monta uma linha de comando; o programa recebe argumentos via
Command::args. - Credencial por processo. Material coletado pelo Torii é sobreposto somente nos filhos de validação e execução.
- Substituição após validação. Reauth falho preserva a sessão anterior.
- Concorrência serializada por escopo de autenticação. Chamadas que herdam o mesmo provider compartilham seu lock; cada alias
aws_profilepossui um lock próprio. - Auditoria sanitizada. Logs usam uma referência curta e não armazenam clipboard, credenciais ou saída completa.
- Target sob controle humano. O alias resolve para configuração local; flags de troca de context, identidade e endpoint são bloqueadas.
- Política pertence ao operador. Install cria rules vazio; setup é o único writer e upgrade nunca toca em rules ou estado operacional.
- Lifecycle herdado pelo target. Todo target indica um provider instalado. Somente depois de allow o Torii lê o ambiente e executa o lifecycle desse provider; o ambiente resultante é aplicado apenas ao processo filho alvo.
- Grant tokenizado. A invocação exata compara todos os tokens e seu tamanho; um grant de prefixo compara somente o prefixo explicitamente escolhido pelo operador. Nenhum grant é reconstruído como linha de shell.
- Consulta de política somente leitura.
torii_policypode ler as regras ativas de um provider ou target, mas não lê ambiente, credenciais, cache ou grants e não altera estado. - Binding AWS humano. Um target
aws_profilefixa profile, região opcional e conta esperada fora do MCP; o Torii remove overrides herdados, bloqueia overrides do agente e confirma a conta por STS antes de cada execução permitida. - Lease humano de target. Um alias target-aware é configurado, mas começa inativo. Depois de avaliar o deny explícito — que encerra a chamada se compatível — e antes de grants, ambiente, sessão ou execução, o dispatcher exige um lease humano ainda válido para aquele binding.
Ordem crítica
validar envelope MCP
|
resolver provider/target e bloquear overrides
|
carregar rules.yaml
|
deny explícito
|
lease humano do target, quando aplicável
|
accept / grant / aprovação da operação
|
revalidar lease; somente se permitido: carregar env e sessão
|
lifecycle do provider de identidade, no balde do escopo
|
quando há identity.expect: conferir identidade pelo probe do provider
|
revalidar lease
|
executar provider
Um refactor que antecipe a leitura de credenciais para antes da decisão é uma regressão de segurança, mesmo que o comando continue sendo bloqueado depois.
Grants temporários
O operador escolhe entre uma invocação exata e um prefixo de argumentos. Prefixo é uma ampliação explícita: qualquer sufixo posterior pode variar, desaparecer ou ser acrescentado. A interface apresenta o vetor como tokens, não como uma linha de shell, e a confirmação é reiniciada quando duração ou escopo mudam.
O arquivo persistido contém somente o tipo, o tamanho e o fingerprint tokenizado do matcher. Arquivos legados ou corrompidos não autorizam chamadas.
Leases de target
Criar um alias não o ativa. O lease autoriza temporariamente o uso daquele binding humano — por exemplo, um context Kubernetes ou um profile AWS — mas não autoriza nenhuma operação por si só. A política Jasper e seus grants continuam sendo avaliados depois.
Todos os aliases configurados continuam visíveis no schema MCP, inclusive inativos. Isso permite que uma chamada a um alias conhecido peça decisão humana; esconder aliases inativos no schema impediria essa fronteira. O estado fica por provider, contém expiração e um digest do binding. Alterar, remover ou recriar o binding invalida o lease anterior.
A interface humana mostra o binding solicitado e os aliases ativos. Substituir desativa todos os demais e ativa o solicitado. Adicionar preserva os ativos. Quando isso resultar em mais de um, um alerta em largura completa fica imediatamente acima das ações, avisa que o agente poderá escolher qualquer alias ativo em operações permitidas e exige manter Adicionar pressionado por 1 segundo; soltar antes interrompe a confirmação. Negar não altera o estado. A duração vai de 1 a 1.440 minutos; o padrão é default_target_minutes, inicialmente 15.
O estado possui revisão, CAS (comparação-e-troca) antes da escrita, um arquivo de lock exclusivo do sistema operacional entre processos e persistência atômica. O handle do lock é liberado automaticamente ao término ou falha do processo; não há TTL ou limpeza por timeout de um lock considerado stale. Assim, uma escolha feita numa janela antiga não restaura um lease depois de target clear ou outra alteração. O lease é conferido novamente antes de ambiente/autenticação e imediatamente antes do launch; uma revogação ou expiração bloqueia uma chamada ainda pendente, mas não encerra um processo já iniciado.
Resolução do executável
command nomeia o CLI sem caminho e sem extensão. No Unix o nome vai para execvp, que já percorre o PATH. No Windows o CreateProcess só acrescenta .exe, o que tornaria invisível qualquer CLI distribuído como wrapper batch — a Azure CLI instala az.cmd e nunca um az.exe. O Torii então percorre o PATH diretório por diretório, tentando as extensões do PATHEXT em ordem, e entrega ao launcher um caminho absoluto.
A busca cobre somente o PATH. O diretório atual e o diretório do próprio binário do Torii ficam de fora de propósito: o CreateProcess os consultaria, e um agente capaz de gravar um arquivo em qualquer um deles poderia sombrear o CLI do provider. Um caminho absoluto também impede que o filho repita a busca sob outro PATH.
Quando o nome resolve para um wrapper .bat ou .cmd, o Windows não tem como carregá-lo sem cmd.exe. O Torii continua não montando linha de comando: os argumentos seguem como vetor até Command::args, e a biblioteca padrão os cita para o cmd.exe. O que precisa valer é que o vetor chegue como dado — &, |, ^, >, %VAR% e !VAR! atravessam o wrapper sem virar comando — e que um argumento que a citação não consiga expressar, como um que contenha quebra de linha, falhe o launch em vez de chegar ambíguo. Ambos estão cobertos por teste.
Ambiente herdado
O processo filho herda o ambiente do processo Torii e recebe por cima .env e a sessão do provider. O Torii não chama env_clear. Portanto:
- não inicie o servidor com segredos globais desnecessários;
- use variáveis como
AZURE_CONFIG_DIReCLOUDSDK_CONFIGno.envdo provider quando o CLI suportar isolamento; - execute o Torii sob a mesma conta local confiável que controla seus arquivos de configuração.
aws_profile é a exceção controlada: para o filho AWS daquele alias, o Torii remove variáveis herdadas de credencial, região e endpoint que poderiam sobrepor o profile fixado. O restante do ambiente continua preservado.
Limites
A versão atual não oferece sandbox de sistema operacional, timeout de processo, streaming de saída, daemon multiusuário, assinatura de providers ou distribuição remota. O runner limita o conteúdo devolvido ao agente, mas o processo pode produzir mais dados internamente antes da captura terminar.
Fluxo de uma chamada
Considere a chamada à tool aws:
{ "args": ["ec2", "describe-instances", "--region", "sa-east-1"] }
1. Dispatch MCP
O servidor confirma que a tool existe, rejeita campos extras e exige pelo menos um item em args.
Em provider target-aware, exige um alias conhecido, recusa flags bloqueadas e resolve o binding, paths e lock daquele target antes de qualquer leitura de ambiente. kubectl_context resolve um context; aws_profile resolve profile, conta esperada e região opcional sem expor esses valores ao MCP. O alias pode aparecer no schema e ainda estar inativo: configuração e lease são estados diferentes.
2. Jasper
O provider é localizado e rules.yaml é carregado. Jasper verifica todos os denies antes dos accepts. O resultado é:
DeniedExplicit: encerra sem credenciais ou processo;Allowed: registra a regra compatível;Unresolved: procura grant ativo e, se necessário, pede decisão humana.
Em uma tool target-aware, o DeniedExplicit retorna antes de qualquer tela de lease. Para os demais caminhos, o dispatcher lê o lease do provider e confere expiração e digest do binding antes de procurar grant ou abrir a aprovação da operação. Se o alias estiver inativo, a janela privada mostra o binding humano solicitado e reúne os aliases já ativos em uma única seção compacta. A duração fica no mesmo card do target solicitado, aceita 1 a 1.440 minutos e começa em default_target_minutes. O humano escolhe Substituir todos os ativos, Adicionar ao conjunto ou Negar. Quando Adicionar criar múltiplos ativos, um alerta em largura completa aparece imediatamente acima das ações e a confirmação só conclui depois de manter o botão pressionado por 1 segundo, com o progresso visível no próprio botão.
Um lease de target não é grant Jasper: ele libera apenas a passagem para a política e para a autenticação daquele alias. Se mais de um alias ficar ativo, o agente pode escolher qualquer um deles nas operações que a política permitir.
A janela de uma decisão Unresolved mostra os argumentos como tokens e cresce por estados: compacta para uma execução, intermediária para grant exact e expandida para edição de prefixo. A largura não muda; o redimensionamento preserva o centro atual da janela. Argumentos longos aparecem com começo, fim e tamanho, e seu conteúdo original pode ser revisado em páginas sem alterar o vetor usado no matcher ou na execução.
Ao escolher uma permissão temporária, o Torii sugere uma fronteira antes do primeiro argumento iniciado por -, desde que existam pelo menos dois tokens anteriores. A sugestão é apenas estrutural, vem acompanhada do motivo e pode ser restaurada depois de uma edição; se a fronteira for precoce ou não existir, a invocação exata permanece selecionada. O operador ainda escolhe livremente exact ou qualquer prefixo válido.
A duração continua editável no campo em minutos, mas ao lado dele há botões de valores padrão — 5, 10, 15, 20 e 30 minutos — para acertar o valor sem arrastar. Quando já existe grant temporário válido no escopo, um primeiro botão oferece o tempo restante do mais antigo deles, no formato m:ss: escolhê-lo faz o novo grant terminar junto com aquele acesso, em vez de sobreviver a ele. Essa é a única duração que pode ter segundos quebrados, e a barra inferior a mostra por extenso.
No editor, os tokens fixos e variáveis ficam em grupos rotulados e um marcador explícito lembra que qualquer prefixo aceita também argumentos futuros. Um resumo destacado acompanha o estado logo acima das ações. Negar mostra brevemente o resultado em coral; Permitir mostra em verde a autorização única ou sua duração antes de prosseguir. O botão de permissão permanece desabilitado até o operador confirmar que revisou invocação, target e escopo. A janela acompanha a altura do corpo: quando as pílulas de argumento ocupam várias linhas, ela cresce até o limite máximo e, a partir dele, o corpo rola — os controles de escopo e duração nunca ficam sob as ações.
Esse feedback visual não muda a ordem de segurança: deny explícito nunca abre a janela, e autenticação só começa depois que uma decisão não explícita foi permitida.
3. Ambiente e sessão
Depois da decisão da operação, o Torii relê o lease. Somente se ele ainda for válido lê o .env compartilhado e, quando houver, o .env do target. Em seguida, o lifecycle garante uma sessão válida no escopo. Para aws_profile, o Torii aplica o profile fixado, remove overrides AWS herdados e consulta STS; conta divergente encerra antes do comando pedido.
4. Runner
O processo é construído conceitualmente assim:
Command::new(provider.command)
.args(provider.args_prefix)
.args(target.args_prefix)
.args(request.args)
.envs(persistent_env)
.envs(auth_env);
Antes do launch, o lease é conferido uma última vez. Stdin do filho é nulo. Stdout e stderr são capturados. Um processo encerrado sem exit code recebe o fallback 143. Um target clear posterior não mata esse processo, mas impede launches que ainda não passaram por essa conferência.
5. Resultado
Torii devolve provider, target quando aplicável, decisão e, quando houve execução, exit code, stdout, stderr e indicador de truncamento. Exit code diferente de zero pertence ao provider e continua visível no resultado.
Concorrência
Chamadas que herdam providers diferentes podem validar sessões independentemente. Chamadas concorrentes que usam o mesmo provider de lifecycle compartilham o lock desse provider. O estado de lease usa também um arquivo de lock exclusivo do sistema operacional e revisão persistida, pois target activate, target clear e servidores MCP podem coexistir; o handle é liberado automaticamente no término do processo, sem TTL ou limpeza por timeout de lock stale.
Aliases aws_profile compartilham lock somente consigo mesmos, pois cada target possui seu próprio escopo de autenticação.
Jasper e políticas
Jasper é o núcleo de decisão do Torii. Ele conhece argumentos e arquivos de política; não executa processos, não carrega credenciais e não implementa a gramática dos CLIs.
Matching por prefixo de tokens
Uma regra é dividida por whitespace. Ela casa quando seus tokens são o prefixo dos itens de args:
| Regra | Args | Resultado |
|---|---|---|
s3 ls | s3, ls | casa |
s3 cp | s3, cp, a, b | casa |
s3 ls | s3api, list-buckets | não casa |
ec2 describe | ec2, describe-instances | não casa |
O algoritmo compara tokens inteiros. Não há prefixo textual parcial.
Uma regra delimitada por /…/flags é avaliada como regex sobre o argv inteiro e casa em qualquer posição, para inspecionar conteúdo (ex.: palavras destrutivas numa query inline). Antes das regras, forbidden_args nega argumentos que abrem canais não inspecionáveis (arquivo, stdin) e ignore_args remove ruído de formatação da avaliação. Veja Escrever políticas e o schema de provider.
Largura mínima de accept
Cada provider define minimum_accept_tokens. AWS usa 2, impedindo um accept amplo como s3. Kubernetes usa 1, permitindo verbos como logs.
Accepts abaixo do mínimo são ignorados e registrados como invalid-accept. Denies não possuem largura mínima, pois bloquear de forma ampla é seguro.
Grants
Uma chamada não resolvida pode receber permissão temporária. O operador escolhe o escopo na janela de autorização:
exact: exige o mesmo vetor de argumentos, inclusive tamanho e ordem;prefix: exige somente os primeirosNargumentos escolhidos. Os argumentos posteriores podem mudar, desaparecer ou ser acrescentados.
O Torii mostra os argumentos como tokens e explica literalmente o alcance antes da confirmação. O provider não infere verbo, recurso ou operação.
Em uma tool target-aware, Jasper só chega a grants depois de o dispatcher confirmar o lease humano do alias. O lease não aparece como regra Jasper e não transforma uma operação em permitida; ele apenas libera a escolha do binding antes da política.
O arquivo grants usa a versão 2 e guarda somente um fingerprint tokenizado do matcher, nunca uma linha de comando reconstruída:
version: "2"
entries:
- expires_at: 1784000000
matcher:
mode: prefix
token_count: 2
sha256: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
Entradas expiradas, malformadas ou de versão desconhecida não autorizam chamadas. O formato legado, que achata argumentos em texto, também é ignorado e exige nova aprovação. Grants nunca alteram rules.yaml.
Decisão explicável
Toda resposta identifica a origem: rules, grant, human-once, human-grant, human-deny ou explicit-deny. Isso permite ao agente compreender por que uma tentativa atravessou ou parou sem expor autenticação.
Providers e targets
Um provider é um diretório local carregado no startup. Ele transforma configuração em uma tool MCP sem virar plugin dinâmico, WASM, pacote OCI ou servidor separado.
Responsabilidades
Um provider declara nome e tool, executável, argumentos prefixados, política, autenticação, ambiente e, opcionalmente, um modo de targeting.
Torii percorre providers/ e carrega diretórios com provider.yaml. Nomes lógicos e tools devem ser únicos. Um provider inválido impede o startup. Nomes de tool e aliases aceitam letras ASCII, dígitos, _, - e ., com no máximo 128 bytes.
Pacotes oficiais
Um pacote é um conjunto declarativo com provider, rules vazio, ambiente inicial e setups read-only opcionais. Pacotes oficiais vivem no catálogo separado torii-mcp/torii-canon-providers; examples/providers/ contém fixtures equivalentes para desenvolvimento.
O catálogo publica hoje:
| Pacote | Tool MCP | Autenticação | Target-aware |
|---|---|---|---|
aws | aws | environment, coletada pelo Torii | não |
aws-profile | aws_profile | inherited por profile humano, com conferência de conta | sim |
az | az | inherited do az login | não |
kubectl | kubectl | delegada ao provider de identidade do target | sim |
snow | snow | inherited | não |
provider install materializa o pacote atomicamente. provider setup <provider> <perfil> é uma operação posterior e explícita sobre a política vazia. O agente não acessa nenhuma dessas capacidades.
Provider simples
AWS usa o provider diretamente. Política, grants, sessão e autenticação vivem na raiz do provider, e a chamada MCP contém apenas args.
args_prefix fixa argumentos confiáveis antes dos argumentos do agente. A política continua avaliando somente args.
Provider target-aware
Kubernetes usa uma tool única kubectl e vários aliases:
providers/kubectl/targets/
├── lab/target.yaml
└── lab_alt/target.yaml
Cada target.yaml associa o alias a um context e indica o provider cujo lifecycle será herdado. O registry publica todos os aliases configurados no schema MCP e exige target na chamada. O executor injeta --context <configurado> antes de args e rejeita flags de override enviadas pelo agente.
O alias começa inativo. Antes de grants Jasper, ambiente ou autenticação, o dispatcher exige um lease humano válido, armazenado no escopo do provider e vinculado por digest ao binding atual. A ativação normal substitui os aliases ativos da tool; adicionar outro é uma escolha humana explícita, pois deixa o agente escolher qualquer alias ativo nas operações permitidas.
O provider alvo compartilha executável e política por padrão. Cada target isola grants e pode substituir regras e variáveis persistentes localmente. Em kubectl_context, cache, credenciais e lock de autenticação pertencem ao provider indicado pelo campo provider.
aws_profile é o segundo modo concreto. A tool recebe um alias como producao; o alias fixa um profile local e uma conta AWS esperada, que não aparecem no schema MCP. O executor bloqueia opções de troca de profile, região e endpoint, aplica o binding somente ao filho e compara a conta STS antes de executar. Nesse modo, cache e lock pertencem ao próprio target, para que aliases de contas diferentes não compartilhem sessão.
Não há ainda uma linguagem genérica de “identidade remota”. O mecanismo de alias é comum, mas cada binding é implementado e validado pelo modo concreto quando há um provider real que o exige.
Sessões de autenticação
Autenticação é um lifecycle separado do Jasper. Todo target autentica pelo provider indicado em identity.provider, num balde de credencial identificado por identity.scope (default: nome do target). Baldes distintos têm sessão, cache e lock independentes; targets só compartilham quando declaram o mesmo escopo. Quando identity.expect está presente, o Torii ainda confirma, via probe auth.identity do provider, que a sessão carrega a identidade esperada antes de executar.
Lease de target antes da sessão
Em qualquer tool target-aware, o alias precisa primeiro de um lease humano válido. Esse lease é separado de credenciais, cache e grants de operação: ele apenas permite que o dispatcher comece a usar o binding daquele target. Sem lease, o Torii não lê .env, cache ou credenciais e não inicia validator, STS ou processo filho.
O lease expira independentemente da sessão. Ele é reavaliado depois da autorização Jasper, antes da sessão e novamente antes do launch. Portanto, remover o lease bloqueia trabalho pendente, mas não apaga credenciais nem interrompe um comando que já começou.
environment
Implementada. O provider declara campos, templates de injeção e validação. O fluxo é:
- carregar a sessão existente após a autorização;
- usar cache curto se houver validação recente;
- executar o comando de validação;
- se inválida, abrir a janela gerada pelos campos;
- manter a mesma janela aberta, bloquear nova submissão e mostrar progresso na barra de status enquanto uma thread de background do subprocesso da GUI executa o validator;
- persistir atomicamente e atualizar o cache;
- devolver as variáveis para a execução autorizada.
Campos secretos usam input mascarado. Campos multilinha têm altura limitada e rolagem interna, para que valores longos não desloquem o restante do formulário. O botão de clipboard aceita export KEY=value, SET KEY=value, $Env:KEY=value e KEY=value, mantendo somente nomes declarados. A barra de status ocupa uma altura fixa e toda a largura no limite inferior da janela, abaixo das ações alinhadas à direita, e alterna entre pronto, progresso, erro e sucesso sem deslocar o layout. Uma candidata recusada reabilita o mesmo formulário sem fechar ou recriar a janela; uma candidata aceita mostra brevemente 👍 Sessão validada. antes do fechamento automático.
inherited
Implementada. Torii não coleta material. Se validate existir, ele roda com .env e o ambiente herdado. Sem validate, o lifecycle registra session-unchecked e não cria cache de validade. torii reauth não se aplica a essa estratégia.
Use .env para apontar stores isolados do provider quando disponível, por exemplo:
AZURE_CONFIG_DIR="C:/Users/voce/.config/torii/providers/az/auth/azure"
Profile AWS com conta vinculada
aws_profile também usa inherited, mas não trata o ambiente inteiro do servidor como identidade. Depois de lease válido e autorização da operação, ele fixa AWS_PROFILE e --profile a partir do alias, remove variáveis AWS herdadas que poderiam ganhar precedência e verifica a conta com STS antes de cada execução. Cache e lock vivem em targets/<alias>/auth/ e targets/<alias>/.session-cache.
O Torii não renova esse profile. Se a sessão expirar ou a conta estiver incorreta, um humano autentica o profile pelo mecanismo nativo do AWS CLI — por exemplo, SSO — e o agente repete a mesma chamada e o mesmo alias.
Estratégias reservadas
session_command e credential_file são desserializadas, mas retornam erro explícito em runtime. Elas não constituem suporte implementado.
Cache e lock
.session-cache guarda o epoch da última validação bem-sucedida. O TTL vem de auth.cache_ttl_seconds, padrão 300 segundos. Um mutex assíncrono por provider de lifecycle impede janelas concorrentes; em aws_profile, o mutex é por alias. A sessão é conferida novamente dentro do lock.
Persistência
Credenciais environment ficam em auth/credentials.env do escopo. A escrita usa arquivo temporário, flush e persistência atômica. Uma tentativa cancelada ou inválida não substitui o arquivo anterior.
Escrever políticas
Para abrir a política no seu editor, com validação antes de aplicar:
torii policy show aws # imprime a política ativa e seu caminho
torii policy edit aws # edita a política compartilhada do provider
torii policy edit kubectl dev # edita a política daquele alias
torii policy edit kubectl dev --create # cria a política do alias
policy edit trabalha sobre uma cópia: ao fechar o editor, o Torii parseia o YAML e compila cada regra, e só então substitui o arquivo vivo. Uma regex inválida ou um YAML malformado é recusado antes de virar política, e o rascunho é preservado para você corrigir. Nada impede editar rules.yaml à mão — o comando existe para que um erro de digitação não vire uma negação inesperada no meio de uma sessão do agente. Detalhes em CLI de controle.
Cada provider possui seu próprio rules.yaml. Em provider target-aware, um rules.yaml dentro do target substitui a política compartilhada somente naquele alias.
Antes de Jasper consultar accept, grants ou uma aprovação de operação para um target-aware, o alias precisa de lease humano válido. O lease autoriza o uso temporário do binding, não a operação; rules e grants continuam sendo necessários. Revogar o lease não apaga grants existentes, mas impede seu uso até que o alias seja ativado novamente.
version: "1.0"
deny:
- "secretsmanager get-secret-value"
- "ecs execute-command"
accept:
- "s3 ls"
- "ec2 describe-instances"
Comece pelo mínimo
Adicione somente operações observadas e necessárias. A ausência de uma operação não impede aprovação humana quando a GUI está habilitada, mas em headless ela será negada.
Use deny para escapes conhecidos
Bloqueie comandos que abrem execução arbitrária, túneis, proxies ou leitura direta de segredos. Deny vence mesmo se uma regra accept mais ampla também casar.
Regras por regex
Uma regra delimitada por /…/flags é tratada como regex e casa em qualquer posição do argv (não só no prefixo). Serve para inspecionar conteúdo — por exemplo, negar palavras destrutivas dentro de uma query SQL inline:
deny:
- "/\\btruncate\\b/i"
- "/copy\\s+into/i"
O padrão é tudo entre a primeira e a última barra; o trecho final são as flags (i case-insensitive, m multi-line, s dot-matches-newline, x ignore-whitespace). Regras regex não estão sujeitas a minimum_accept_tokens. Um regex inválido faz a avaliação falhar fechada (erro, nunca allow silencioso), então cubra os exemplos com um teste.
Regex é best-effort: concatenação dinâmica e stored procedures escapam. Trate-o como defense-in-depth e auditoria — a fronteira dura deve estar no próprio serviço (ex.: um role read-only). Veja os providers snow e az em examples/providers/ para políticas completas.
Posicione flags depois da ação
Jasper avalia prefixos desde o primeiro item. Prefira:
get pods -n equipe
Evite:
-n equipe get pods
O segundo formato não casa com get pods e será não resolvido.
Escolha grants conscientemente
Ao permitir temporariamente, escolha entre a invocação exact e um prefixo de argumentos. A interface pode sugerir um prefixo imediatamente antes do primeiro argumento iniciado por -, quando há pelo menos dois tokens anteriores. Essa é uma sugestão pelo formato do vetor, não a dedução de uma operação semântica; revise e mova a fronteira quando necessário.
Um prefixo de get pods, por exemplo, permite chamadas futuras que comecem exatamente por esses dois tokens no mesmo target; argumentos posteriores podem mudar, desaparecer ou ser acrescentados. Mesmo quando todos os argumentos atuais estão fixos, um prefixo ainda permite acrescentar novos argumentos no futuro.
Use o prefixo somente quando o conjunto autorizado estiver claro para o operador. A invocação exata exige o mesmo número, valores e ordem de argumentos. Não passe segredos em argumentos de CLI.
Teste fronteiras
Ao alterar matching, cubra pelo menos:
- deny e accept para a mesma ação;
- prefixos parecidos como
s3es3api; - accept abaixo do mínimo;
- comando não listado;
- grant expirado e ativo.
Configurar AWS
O pacote canônico de desenvolvimento está em examples/providers/aws/. Este guia cobre credenciais temporárias coletadas e validadas pelo Torii. Para profiles locais com aliases humanos e verificação de conta, veja AWS por profile e aliases. O lease de target não altera este provider simples: a tool aws continua recebendo somente args e não exige alias.
Instale e, opcionalmente, aplique o setup curado:
torii provider install ./examples/providers/aws
torii provider setup aws readonly
Install recusa providers/aws/ existente. Setup recusa uma política ativa não vazia.
Provider
Os pontos essenciais são:
tool: aws
command: aws
policy:
minimum_accept_tokens: 2
auth:
strategy: environment
validate:
command: aws
args: [sts, get-caller-identity]
Os três campos temporários são declarados e injetados como:
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
AWS_SESSION_TOKEN
Região e formato de saída
Use o .env do provider para valores persistentes não secretos:
AWS_REGION="sa-east-1"
AWS_DEFAULT_REGION="sa-east-1"
AWS_PAGER=""
Evitar pager é importante porque stdin do processo filho é nulo.
Política inicial curada
O pacote instala uma política vazia. A allowlist portada do AWS Gate só entra em vigor com provider setup aws readonly; ela inclui operações comuns de STS, EC2, Lambda, Step Functions, CloudWatch Logs, ECS, ECR, Secrets Manager, Glue, EKS e SSM. Operações que retornam valores de segredo, credenciais, tokens ou execução remota possuem deny explícito.
Mesmo sem operações de escrita, há riscos que precisam de revisão humana:
- configurações Lambda podem conter variáveis sensíveis;
- parâmetros SSM podem conter segredos dependendo da convenção da organização;
- uma operação read-only ainda pode revelar dados confidenciais.
O template é um ponto de partida útil, não uma política universal pronta para produção. Remova accepts incompatíveis com sua classificação de dados e mantenha IAM de menor privilégio.
Renovação
torii reauth aws
Cole atribuições copiadas do portal ou preencha os campos. Torii testa a identidade antes de substituir a sessão. O arquivo antigo permanece se o usuário cancelar ou se sts get-caller-identity falhar.
Configurar AWS por profile e aliases
Use este fluxo quando cada conta AWS já é representada por um profile local humano, por exemplo uma sessão SSO. Ele é separado do provider aws, que continua sendo o fluxo de credenciais temporárias coletadas pelo Torii.
O pacote cria a tool MCP aws_profile:
torii provider install ./examples/providers/aws-profile
torii provider setup aws-profile readonly
Depois o humano cria um alias. O alias, e não o profile, é o único identificador que o agente recebe:
torii target add aws_profile producao `
--profile empresa-producao `
--account-id 111122223333 `
--region sa-east-1
Profile, conta esperada e região ficam no bloco identity do target.yaml local (identity.profile, identity.expect, e region). O escopo de credencial recebe o nome do profile, então aliases do mesmo profile compartilham sessão e profiles distintos ficam isolados. O schema MCP, os resultados e a auditoria mostram somente producao.
Ativar o alias por tempo limitado
Criar o alias não o torna disponível para execução. Antes de deixar um agente usá-lo, o humano concede um lease:
torii target activate aws_profile producao --for 30
torii target status aws_profile
--for aceita de 1 a 1.440 minutos e, se omitido, usa default_target_minutes (15). A ativação normal desativa todos os outros aliases ativos de aws_profile. Para manter os existentes, use --add conscientemente:
torii target activate aws_profile homologacao --for 30 --add
Com mais de um alias ativo, o agente pode escolher qualquer um deles em operações permitidas. Prefira a substituição normal e políticas/IAM mais restritivos para produção. Para revogar todos os aliases ativos sem mexer em grants, sessão, cache ou configuração, use torii target clear aws_profile.
Binding de conta
Depois de descartar um deny explícito, o dispatcher exige primeiro o lease humano do alias. Só então consulta grants ou autorização Jasper e, após essa decisão, fixa o profile configurado no processo filho, bloqueia --profile, --region, --endpoint-url, --no-sign-request e opções TLS equivalentes enviadas pelo agente. Credenciais AWS, região e endpoint herdados do processo servidor são removidos desse filho para não sobrepor o profile.
Antes do comando solicitado, o Torii executa internamente sts get-caller-identity --output json com o mesmo binding e compara a conta com os 12 dígitos configurados. A comparação ocorre em toda chamada permitida; divergência, erro de identidade ou saída inválida impede o comando solicitado. Os números de conta não são devolvidos ao agente.
O balde de credencial do alias (identities/<profile>/) tem cache, .identity-cache e lock próprios. Isso evita compartilhar estado entre aliases de contas diferentes; aliases do mesmo profile reaproveitam o balde de propósito.
Renovar a sessão correta
Não existe tool MCP de reauth, e torii reauth aws_profile producao deliberadamente não tenta alterar a sessão. Um profile pode ser SSO, estático ou usar outro mecanismo externo; o Torii não consegue trocar esse estado de forma atômica e validada.
Quando o alias informar que a identidade está ausente ou pertence a outra conta, o agente deve pedir que um humano autentique o profile configurado pelo fluxo nativo apropriado e então repetir a chamada com o mesmo alias. Um alias sem lease abre a decisão humana de target; em headless, a tentativa é negada. Para um profile SSO, por exemplo:
aws sso login --profile empresa-producao
Não peça ao agente para escolher outro profile, editar target.yaml ou tentar flags de override. Se a conta desejada mudou, o humano revisa ou cria um alias no control plane.
Configurar Kubernetes
Torii publica uma única tool kubectl. O campo MCP target escolhe um alias cadastrado pelo humano; o agente nunca escolhe o context real.
Provider único
version: "1"
name: kubectl
tool: kubectl
command: kubectl
targeting:
mode: kubectl_context
Cadastre um context já existente no kubeconfig:
torii provider install aws
torii target add kubectl dev --context mdb-k8s-dev-ia --provider aws
torii target add kubectl hml --context mdb-k8s-hml-ia --provider aws
torii target list kubectl
torii target show kubectl dev
torii target activate kubectl dev --for 30
target add executa kubectl config get-contexts <context> -o name e só grava o target quando o context existe. O --provider indica o provider de identidade (o campo identity.provider do target): quem autentica a sessão usada por aquele context. Ele precisa estar instalado e não pode exigir target. O alias criado começa inativo: target activate concede um lease humano de 1 a 1.440 minutos (15 por padrão) antes de grants, ambiente ou autenticação. Reinicie o servidor MCP depois de adicionar ou remover targets, pois o registry e o enum do schema são construídos no startup; aliases inativos continuam no enum.
Identidade e escopo de credencial
Cada target tem um bloco identity:
version: "1"
name: dev
context: mdb-k8s-dev-ia
identity:
provider: aws # quem roda o lifecycle de autenticação
scope: dev # balde de credencial; default = nome do target
expect: "009160073200" # opcional; conferido pelo probe do provider antes de executar
O escopo (identity.scope) é a chave do balde de credenciais. Por padrão vale o nome do target, então dev e hml autenticam de forma independente: torii reauth kubectl dev renova só aquele balde e os dois podem ter lease ativo ao mesmo tempo sem uma sessão derrubar a outra. Para compartilhar de propósito uma sessão entre vários contexts da mesma conta, dê o mesmo --scope aos targets.
O expect é opcional. Quando presente, o Torii roda o probe auth.identity do provider de identidade (para o aws, um sts get-caller-identity lendo o campo Account) e recusa a execução se a identidade ativa não bater — transformando um 401/conta-errada silencioso em erro explícito antes de qualquer comando tocar o cluster. Exigir expect sem o provider declarar o probe é erro de configuração.
torii target add kubectl dev --context mdb-k8s-dev-ia --provider aws --scope dev --expect 009160073200
Uma chamada do agente:
{
"target": "lab",
"args": ["get", "pods", "-n", "default"]
}
vira conceitualmente:
kubectl --context local-context get pods -n default
Depois de confirmar que nenhum deny explícito corresponde à chamada, o Torii exige lease humano válido para o alias antes de consultar grants Jasper ou abrir aprovação da operação. Se o lease estiver inativo, a janela privada mostra o context e os aliases ativos; o humano pode substituir os ativos, adicionar outro ou negar. Quando a adição criar múltiplos ativos, o alerta aparece junto às ações e exige manter Adicionar pressionado por 1 segundo. Depois que a política permite a chamada, o Torii relê o lease e executa o lifecycle de autenticação do provider referenciado pelo target. Se a sessão precisar ser coletada ou renovada, a interface e o validator são os desse provider. Após sucesso, somente o ambiente necessário é sobreposto ao processo kubectl.
Um deny explícito encerra antes de ler ambiente, cache ou credenciais e antes de executar o lifecycle desse provider. Uma falha ou cancelamento no preflight impede a execução do kubectl solicitado. Nesta versão, instalar o provider autenticador também publica sua tool MCP; deixe suas rules em default deny se o agente não precisar usá-la diretamente.
Flags capazes de trocar identidade ou endpoint, incluindo --context, --kubeconfig, --cluster, --user, --token e --server, são recusadas nos argumentos MCP. A lista completa está no contrato de provider.
Política read-only
O rules.yaml do provider é compartilhado por padrão. Um targets/<alias>/rules.yaml existente substitui a política compartilhada somente naquele target.
deny:
- "exec"
- "attach"
- "port-forward"
- "proxy"
- "config"
- "delete namespace"
accept:
- "get pods"
- "get deployments"
- "describe pod"
- "logs"
- "rollout status"
Grants temporários e .env ficam isolados no diretório do target. O .env do target sobrepõe chaves do .env compartilhado. Credenciais, .session-cache, .identity-cache e lock vivem no balde do provider de identidade em providers/<provider>/identities/<scope>/, isolados por escopo; dois targets só os compartilham quando declaram o mesmo scope. O conjunto de leases fica no escopo da tool, com uma entrada por target: ativar sem --add substitui todos os aliases ativos; adicionar outro significa que o agente poderá escolher qualquer alias ativo até a expiração ou target clear.
RBAC continua obrigatório
Jasper só decide se a tentativa atravessa. A identidade selecionada no kubeconfig deve ter RBAC de menor privilégio. Uma política local permissiva não amplia RBAC; um RBAC permissivo também não substitui a política local.
Todo target exige identity.provider. torii reauth kubectl dev delega para o lifecycle desse provider no escopo do target. Um provider inherited sem validator passa por esse lifecycle como session-unchecked; um provider inherited com validator (login via SSO/profile externo) não pode ser renovado pelo Torii — o reauth aponta o humano para o fluxo nativo.
Configurar Azure
O pacote canônico é az; a fixture de desenvolvimento equivalente está em
examples/providers/az/. A tool MCP é az e recebe somente args: este provider não é
target-aware e não exige alias nem lease.
torii provider install az
torii provider setup az readonly
Sessão herdada do az login
tool: az
command: az
policy:
minimum_accept_tokens: 2
auth:
strategy: inherited
cache_ttl_seconds: 300
A Azure CLI guarda os tokens do az login em ~/.azure. O Torii herda essa sessão: não
coleta campos, não grava credenciais e não substitui o token. Consequências operacionais:
- quem autentica é o humano, no terminal, com
az login(ouaz login --tenant <tenant>); torii reauth aznão tem material renovável para trocar — a sessão é do CLI, não do Torii;- não há validator declarado, então a auditoria registra
session-unchecked: o Torii não confirma a validade da sessão antes de executar. Um token expirado aparece como erro do próprioazna resposta da chamada; - a assinatura ativa é a do perfil local. O agente não escolhe assinatura, e nada impede que
a assinatura ativa mude por fora — confira com
az account showantes de liberar uso.
Se você precisa de isolamento por assinatura, prefira contas separadas no sistema
operacional a tentar alternar az account set durante o uso do agente.
Política: dois tokens de piso
Comandos da Azure CLI têm a forma grupo verbo (vm list, group show), e o pacote define
minimum_accept_tokens: 2 para um accept não ficar amplo demais. Grupos com subcomandos
sensíveis precisam de regras mais específicas do que dois tokens: keyvault secret list
libera nomes, keyvault secret show devolve o valor — são regras diferentes e o segundo
está no deny.
O que o setup readonly nega
Além de não aceitar escrita, o setup nega explicitamente:
| Categoria | Exemplos negados |
|---|---|
| emissão de credencial ou token | account get-access-token, aks get-credentials, acr login, storage account keys list, storage account show-connection-string, ad sp credential reset |
| leitura do valor de segredo | keyvault secret show, keyvault secret download, keyvault key download, keyvault certificate download |
| execução remota | vm run-command invoke, ssh vm |
| canais que escapam da curadoria | rest, interactive |
az rest merece atenção: ele fala com a API do Azure Resource Manager diretamente, o que
tornaria toda a curadoria de grupos e verbos irrelevante. Mantenha-o no deny.
O accept cobre descoberta e leitura de metadados — account, group, resource, vm,
vmss, disk, network, storage account (apenas metadados), aks, acr, webapp,
functionapp, keyvault (cofre e nomes), role assignment, policy, monitor e tag.
Revise a lista conforme a classificação de dados da sua assinatura: uma operação de leitura
ainda pode revelar informação confidencial, por exemplo variáveis de aplicação em
webapp config show.
Ambiente
Use o .env do provider para valores persistentes não secretos:
AZURE_CORE_OUTPUT="json"
AZURE_CORE_ONLY_SHOW_ERRORS="true"
Não coloque credenciais nesse arquivo: a sessão vem do az login. Como o stdin do processo
filho é nulo, prefira comandos que não abram prompt interativo — outro motivo para
interactive estar negado.
RBAC continua obrigatório
A política local decide se a tentativa atravessa; o RBAC da identidade decide o que ela pode fazer de fato. Uma política permissiva não amplia RBAC, e um RBAC amplo não é compensado por regras locais. Use um principal de menor privilégio para o uso do agente.
Configurar Snowflake
O pacote canônico é snow; a fixture equivalente está em examples/providers/snow/. A tool
MCP é snow, recebe somente args e não é target-aware.
torii provider install snow
torii provider setup snow readonly
Este provider é o exemplo de referência para inspeção de conteúdo: o risco não está no subcomando, está na query SQL que viaja como argumento.
Sessão herdada da connection
tool: snow
command: snow
auth:
strategy: inherited
cache_ttl_seconds: 300
A connection default vem de ~/.snowflake/config.toml. O Torii herda essa sessão, não
coleta credencial e não a renova: torii reauth snow não tem material para trocar. Sem
validator declarado, a auditoria registra session-unchecked.
As três camadas da política
policy:
minimum_accept_tokens: 1
forbidden_args:
- "-f"
- "--filename"
- "-i"
- "--stdin"
ignore_args:
leading: 0
flags: ["--format", "-o", "--output", "-x"]
1. forbidden_args fecha os canais não inspecionáveis. Uma query lida de arquivo ou de
stdin não está no argv, então nenhuma regra de conteúdo a enxerga. Sem esse bloco, as regras
de conteúdo abaixo seriam decoração: bastaria snow sql -f drop.sql. Um argumento proibido é
negado com fonte forbidden-arg, em qualquer posição, antes de qualquer regra ser avaliada.
O casamento aceita --filename e --filename=valor.
2. ignore_args remove ruído da avaliação. Flags de formatação são descartadas apenas
para avaliar a política, nunca do comando executado. Isso evita que um valor de --format
acione um match por engano. Uma flag nua também descarta o token de valor seguinte
(--format json); a forma --format=json descarta o token único.
3. As regras inspecionam a query. O setup readonly usa regex, que casa em qualquer
posição do argv, e libera SQL inline:
deny:
- "/\\btruncate\\b/i"
- "/\\bdrop\\b/i"
- "/\\bdelete\\b/i"
- "/\\bupdate\\b/i"
- "/\\binsert\\b/i"
- "/\\bmerge\\b/i"
- "/\\balter\\b/i"
- "/\\bcreate\\b/i"
- "/\\bgrant\\b/i"
- "/\\brevoke\\b/i"
- "/execute\\s+immediate/i"
- "/copy\\s+into/i"
- "/\\bput\\b/i"
accept:
- "sql -q"
- "sql --query"
Como deny vence accept, snow sql -q "select 1; truncate t" é barrado mesmo casando o
accept — é justamente o caso que o matching por prefixo sozinho não pegaria.
O limite honesto do regex
Regex sobre SQL é best-effort, não parser. Escapam dele, entre outros:
- concatenação dinâmica e SQL montado em stored procedure;
- falsos positivos quando a palavra aparece isolada em contexto inofensivo: dentro de uma
string literal, de um comentário SQL ou de um identificador citado como
"DROP"(identificadores comuns comoupdated_atnão casam, porque_conta como caractere de palavra e não há fronteira\bali); - variações que a lista não previu.
Por isso a fronteira dura é um role read-only no próprio Snowflake. As regras locais são
defense-in-depth, auditoria e experiência de uso: elas transformam um erro do agente em
negação explícita e barata, em vez de um erro remoto. Um regex inválido faz a avaliação
falhar fechada (erro, nunca allow silencioso), então cubra suas regras com um teste — veja
tests/example_policies.rs.
Fixe a connection antes de liberar o agente
O accept sql -q casa por prefixo, então argumentos posteriores continuam livres. Se a sua
instalação usa mais de uma connection, conta ou role, o agente poderia acrescentar uma flag
de conexão à mesma query permitida. Recomendações, em ordem de eficácia:
- deixe no
config.tomlapenas a connection que o agente pode usar, com um role read-only; - acrescente ao
provider.yamlas flags de conexão aoforbidden_args, por exemplo--connection,-c,--account,--user,--role,--warehouse,--database,--private-key-filee--temporary-connection, para que uma troca de identidade seja negada antes de qualquer regra; - nunca dependa apenas das regras de conteúdo para decidir onde a query roda.
Este provider não é target-aware: ao contrário de kubectl e aws_profile, o Torii não
injeta nem bloqueia binding de conexão por conta própria aqui.
Ambiente
SNOWFLAKE_DEFAULT_CONNECTION_NAME="leitura"
Não coloque credenciais no .env: a connection e suas chaves vivem no config.toml do
Snowflake CLI. Como o stdin do processo filho é nulo, evite comandos que abram prompt.
Operar providers e sessões
O control plane é humano. Nenhum comando desta página aparece no MCP.
Catálogo e providers locais
torii provider search
torii provider search kubernetes
torii provider list
Search consulta o catálogo; list inspeciona apenas instalações locais e mostra tool, nome, executável, versão e origem.
Instalar
torii provider install aws
torii provider install ./pacotes/aws
torii provider install ./pacotes/aws.zip
torii provider install https://example.org/aws.tar.gz
O install valida manifest, provider e política base; extrai em staging e faz rename. Um destino existente é recusado. O rules.yaml ativo nasce vazio.
Aplicar setup
torii provider setup aws readonly
Pacotes podem oferecer vários setups read-only. Setup é o único comando que escreve em rules e recusa substituir uma política que já tenha accepts ou denies.
Atualizar
torii provider upgrade aws
Upgrade usa a origem gravada no lock. Ele substitui provider.yaml e metadados/setups do pacote. Rules ativo, .env, grants, targets, cache e autenticação não são abertos para escrita.
Inicializar e descobrir paths
torii init
torii config-dir
Init cria somente settings e raiz. Providers são sempre uma escolha explícita.
Reautenticar
torii reauth aws
torii reauth kubectl meu_dev
Reauth aplica-se a autenticação gerenciada; inherited sem validator não possui material renovável pelo Torii. O reauth de um target delega ao lifecycle do provider de identidade (identity.provider), no balde do escopo do target. Um provider inherited com validator (login externo via SSO/profile) não é renovado por reauth: o humano autentica pelo fluxo nativo e o agente repete o alias.
Targets
torii target add kubectl meu_dev --context contexto-local --provider aws
torii target add aws_profile producao --profile empresa-producao --account-id 111122223333 --region sa-east-1
torii target list kubectl
torii target show kubectl meu_dev
torii target activate kubectl meu_dev --for 30
torii target status kubectl
torii target activate aws_profile homologacao --for 30 --add
torii target clear aws_profile
torii target remove kubectl meu_dev --force
O primeiro comando cria um binding Kubernetes; o segundo cria um binding AWS de profile e conta esperada. Profile e conta aparecem somente nos comandos humanos target list e target show, não no MCP. Criar não ativa: todos os aliases target-aware começam sem lease, mas continuam anunciados no schema MCP.
target activate libera temporariamente um alias. Sem --add, ele substitui todos os aliases ativos daquela tool; com --add, preserva os existentes. A duração aceita 1 a 1.440 minutos e usa default_target_minutes (15) quando --for não é informado. Ao manter mais de um ativo, aceite deliberadamente que o agente poderá escolher qualquer alias ativo em uma operação permitida. target status mostra os leases e expirações. target clear revoga somente leases: não remove target, rules, grants, .env, cache ou credenciais e não encerra processos já iniciados.
Reinicie o servidor MCP após install, upgrade ou mudança no conjunto de targets. A criação/remoção muda o enum do schema; ativar, limpar ou aguardar a expiração não muda o enum. rules.yaml e o estado de lease são relidos durante cada chamada.
Integrar agentes e instalar o hook
O Torii integra Codex, Claude Code, Gemini CLI, Cursor, Antigravity, opencode, GitHub Copilot (VS Code e CLI) e pi. A integração é control plane humano: nenhum comando desta página aparece como tool MCP.
Liste os adapters disponíveis e o que cada um suporta:
torii agent list
Registre o servidor MCP stdio torii em um cliente:
torii agent install <agent>
Nem todo cliente oferece as duas metades da integração. O hook depende de o cliente publicar um evento antes da execução de shell:
| Adapter | MCP | Hook |
|---|---|---|
codex, claude, gemini, cursor, antigravity | sim | sim |
opencode, copilot, copilot-cli | sim | não existe no cliente |
pi | somente através de uma extensão MCP instalada por você | não implementado pelo Torii |
Para os adapters sem hook, --hook é recusado antes de qualquer escrita, e agent status informa hook not supported. Isso não é uma limitação do Torii: aqueles clientes não expõem um ponto de interceptação equivalente, então o Torii não pode prometer bloquear a chamada direta ao aws ou ao kubectl neles.
A configuração fixa o caminho absoluto do executável Torii e o TORII_CONFIG_DIR usado durante a instalação. Reinicie o cliente para carregar a alteração.
Descoberta e autenticação
O MCP instrui o agente a consultar torii_policy antes de selecionar uma operação. A tool devolve, somente para leitura, os accept e deny do provider ou target ativo; ela não executa CLIs e não lê ambiente ou credenciais.
O agente não recebe tools de reauth, ativação, limpeza ou edição de targets. Quando uma chamada target-aware seleciona um alias inativo, o Torii pede ao humano um lease para o binding antes de consultar grants, ambiente ou sessão. Em headless, isso termina em negação. Para trocar ou renovar uma sessão gerenciada antes da chamada, o humano usa torii reauth <provider-tool> [target] no control plane.
O agente não deve tratar um alias listado no schema como ambiente ativo: a lista mostra aliases configurados, não leases. Se Adicionar criar vários aliases ativos, a interface alerta o humano junto às ações e exige manter o botão pressionado por 1 segundo. Depois da confirmação, o agente poderá selecionar qualquer alias ativo nas operações permitidas; por isso deve escolher pelo alias semântico pedido pelo humano e não tentar alternar targets por conta própria.
Para um target aws_profile, a conta ou o profile não são expostos ao agente. Se o Torii informar identidade ausente ou conta divergente, o agente pede que o humano autentique o profile já configurado pelo fluxo nativo AWS e repete o mesmo alias. Ele não tenta reauth, troca de target nem flags --profile/--region.
Se o comando for executado por
cargo run, o cliente ficará apontando para o binário emtarget/debug. Prefira uma release instalada antes de configurar o agente.
Arquivos alterados
| Adapter | MCP | Chave | Hook |
|---|---|---|---|
| Codex | $CODEX_HOME/config.toml | mcp_servers | $CODEX_HOME/hooks.json |
| Claude Code | ~/.claude.json | mcpServers | ~/.claude/settings.json |
| Gemini CLI | $GEMINI_CLI_HOME/.gemini/settings.json | mcpServers | o mesmo settings.json |
| Cursor | ~/.cursor/mcp.json | mcpServers | ~/.cursor/hooks.json |
| Antigravity | ~/.gemini/config/mcp_config.json | mcpServers | ~/.gemini/config/hooks.json |
| opencode | $XDG_CONFIG_HOME/opencode/opencode.json | mcp | — |
| Copilot no VS Code | mcp.json do perfil do usuário | servers | — |
| Copilot CLI | $COPILOT_HOME/mcp-config.json | mcpServers | — |
| pi | ~/.pi/agent/mcp.json | mcpServers | — |
Sem as variáveis de override, Codex usa ~/.codex, Gemini usa ~/.gemini, opencode usa ~/.config/opencode, a CLI do Copilot usa ~/.copilot e o pi usa ~/.pi/agent. Quando CLAUDE_CONFIG_DIR está definido, os arquivos do Claude passam a ser <dir>/.claude.json e <dir>/settings.json.
O perfil de usuário do VS Code depende do sistema: %APPDATA%\Code\User no Windows, ~/Library/Application Support/Code/User no macOS e $XDG_CONFIG_HOME/Code/User no Linux. Use TORII_COPILOT_HOME para apontar outro perfil, por exemplo o do VS Code Insiders.
Os overrides TORII_CURSOR_HOME, TORII_ANTIGRAVITY_HOME, TORII_OPENCODE_HOME, TORII_COPILOT_HOME, TORII_COPILOT_CLI_HOME e TORII_PI_HOME selecionam outro diretório, principalmente para automação e testes.
O Antigravity compartilha ~/.gemini/config/ entre IDE e CLI, então uma instalação atende as duas superfícies. Esse diretório é vizinho do Gemini CLI, mas os arquivos são distintos: o Gemini usa ~/.gemini/settings.json e o Antigravity usa ~/.gemini/config/mcp_config.json. Os dois adapters podem coexistir sem se sobrescrever.
Cada cliente recebe o formato que ele mesmo entende: opencode declara type: local com o comando em vetor e o ambiente em environment; a CLI do Copilot chama stdio de local e exige a lista tools; Claude e Copilot no VS Code usam type: stdio. O Torii escreve apenas a entrada torii e preserva o resto do arquivo.
Se o opencode já mantiver a configuração em opencode.jsonc, o Torii recusa a instalação em vez de reescrever o arquivo: ele só edita JSON puro e a reescrita descartaria seus comentários. Adicione a entrada manualmente ou migre para opencode.json.
O instalador preserva outras configurações. Se já existir um servidor MCP torii diferente, ele para sem substituí-lo.
pi exige uma extensão MCP
O pi não fala MCP nativamente: o suporte vem de extensões da comunidade instaladas em ~/.pi/agent/extensions/. O Torii grava ~/.pi/agent/mcp.json no formato compartilhado pelos outros hosts, mas quem lê esse arquivo é a extensão, não o pi.
Por isso a instalação avisa e pede confirmação:
torii agent install pi
torii agent install pi --yes
Sem uma extensão MCP no pi, o arquivo é simplesmente ignorado e nada funciona. Se você não sabe de qual extensão se trata, não prossiga: instale primeiro a extensão MCP e só depois a integração do Torii. Em ambiente sem terminal interativo, a instalação é recusada até que --yes confirme a decisão.
Hook opcional
Para instalar também o guard de execução direta, em um adapter que ofereça hook:
torii agent install <codex|claude|gemini|cursor> --hook
Cada adapter usa o evento nativo do cliente:
| Adapter | Evento protegido | Tool de shell |
|---|---|---|
| Codex | PreToolUse | Bash |
| Claude Code | PreToolUse | Bash |
| Gemini CLI | BeforeTool | run_shell_command |
| Cursor | beforeShellExecution | shell do agente |
| Antigravity | PreToolUse com matcher | run_command |
Antes da chamada, o cliente envia o comando ao próprio Torii. O guard carrega o registry atual e compara o executável tentado com o campo command de cada provider.
Cada cliente também tem seu formato de arquivo e de resposta. O Antigravity guarda hooks por grupo nomeado, não em um objeto hooks compartilhado: o Torii cria o grupo torii-provider-boundary, é dono dele por inteiro e o remove por completo na desinstalação, sem tocar nos seus outros grupos. A negação sai como {"decision":"deny","reason":"…"}.
Com um provider que declara command: kubectl, esta tentativa é bloqueada:
kubectl get pods
A resposta orienta o agente a chamar a tool MCP kubectl, selecionar um target anunciado e enviar somente os argumentos posteriores ao executável. Nome com extensão, caminho absoluto, comandos encadeados e invocações comuns por outro shell também são reconhecidos.
O hook é do Torii, não do pacote. Providers não carregam scripts ou configuração específica de agentes. Instalar, atualizar ou remover um provider muda dinamicamente o conjunto protegido sem reescrever a configuração do agente.
Se o input do hook for inválido ou o registry não puder ser carregado, a chamada de shell é negada. Com nenhum provider instalado, não existe executável para bloquear.
Estado e remoção
Inspecione a integração:
torii agent status <agent>
O status diferencia conteúdo gerenciado pelo Torii de uma entrada preexistente.
Remova somente o guard, preservando o MCP:
torii agent uninstall <agent-com-hook> --hook
Ou remova toda a integração gerenciada:
torii agent uninstall <agent>
O Torii mantém metadados em <TORII_CONFIG_DIR>/agents/<adapter>.json para remover somente as entradas que criou. Se uma entrada gerenciada tiver sido alterada depois, a remoção para em vez de apagar configuração do usuário.
Limite de segurança
O hook bloqueia o caminho comum e torna a negação visível ao agente, mas não é uma sandbox nem uma fronteira completa. Um processo com acesso às mesmas credenciais ainda pode tentar outra biblioteca, outro executável ou um mecanismo não coberto pelo hook.
Use as camadas em conjunto:
- instruções MCP orientam o agente;
- o hook bloqueia chamadas diretas reconhecidas;
- o sandbox do agente limita caminhos alternativos;
- credenciais e identidades de menor privilégio limitam o impacto real.
Em opencode, Copilot e pi a camada 2 não existe. Ali o agente continua podendo chamar aws ou kubectl pelo shell dele sem passar pelo Torii, então as camadas 3 e 4 carregam sozinhas o peso: use o sandbox do cliente e credenciais de menor privilégio, e não trate a política do Torii como se fosse a única barreira.
Consulte as referências oficiais de hooks do Codex, hooks do Claude Code, hooks do Gemini CLI e hooks do Cursor, além do modelo de segurança do Torii.
Layout de configuração
O diretório padrão é ~/.config/torii. TORII_CONFIG_DIR substitui a raiz inteira.
~/.config/torii/
├── settings.yaml
├── torii.log
└── providers/
├── aws/
│ ├── provider.yaml
│ ├── rules.yaml
│ ├── .env
│ ├── .torii-package/
│ │ ├── manifest.yaml
│ │ ├── lock.yaml
│ │ └── content/
│ ├── grants
│ └── identities/
│ └── aws/
│ ├── .session-cache
│ ├── .identity-cache
│ └── auth/credentials.env
├── kubectl/
│ ├── provider.yaml
│ ├── rules.yaml
│ ├── .env
│ ├── .target-authorizations.yaml
│ ├── .target-authorizations.lock
│ └── targets/
│ └── lab/
│ ├── target.yaml
│ ├── rules.yaml
│ ├── .env
│ └── grants
└── aws-profile/
├── provider.yaml
├── .target-authorizations.yaml
├── .target-authorizations.lock
├── identities/
│ └── empresa-producao/
│ ├── .session-cache
│ ├── .identity-cache
│ └── auth/
└── targets/
└── producao/
└── target.yaml
.torii-package/ existe somente em instalações gerenciadas e contém origem, digest e setups. rules.yaml e .env ficam fora desse diretório porque pertencem ao operador. Rules do target é opcional e substitui o compartilhado; .env do target sobrepõe chaves compartilhadas. Sessão, cache, .identity-cache, credenciais e lock vivem sempre no provider de identidade em identities/<scope>/, isolados por escopo — não no diretório do target. Um provider não target-aware autentica num escopo com o nome da própria tool; targets isolam por identity.scope (default: nome do target) e só compartilham o balde quando declaram o mesmo escopo.
.target-authorizations.yaml é diferente de grants: é o estado de lease dos aliases daquele provider. Ele guarda versão, revisão, alias, digest do binding e expiração. O digest faz um lease expirar logicamente quando o target.yaml correspondente muda, mesmo antes do horário previsto. .target-authorizations.lock é o arquivo usado para lock entre processos durante mudanças nesse estado: usa exclusão do sistema operacional (share lock no Windows e flock no Unix), e o handle é liberado automaticamente se o processo termina ou falha. Não há TTL ou limpeza por timeout de um lock considerado stale; não o crie, remova ou sincronize manualmente.
settings.yaml
max_output_bytes: 262144
default_grant_minutes: 2
default_target_minutes: 15
max_output_bytes limita o conteúdo combinado devolvido; default_grant_minutes define o valor inicial da aprovação temporária de uma operação; default_target_minutes define o valor inicial do lease de um alias target-aware. Leases aceitam de 1 a 1.440 minutos.
Arquivos gerenciados
grants: arquivo YAML versão2com expiração e fingerprint do matcher; o formato legado de epoch, tab e regra não é reutilizado;.target-authorizations.yaml: leases temporários por provider, com revisão e digest do binding; não concede operações Jasper;identities/<scope>/.session-cache: epoch da última validação da sessão daquele escopo;identities/<scope>/.identity-cache: epoch e identidade confirmada pelo probeauth.identity;identities/<scope>/auth/credentials.env: material sensível;torii.log: auditoria append-only best-effort.
Restrinja acesso ao diretório com permissões do sistema operacional e não o sincronize em repositórios ou telemetria.
Schema de provider e target
provider.yaml usa version: "1".
Campos de topo
| Campo | Obrigatório | Descrição |
|---|---|---|
version | sim | deve ser "1" |
name | sim | identidade lógica única |
tool | sim | nome MCP único; torii_policy é reservado pelo Torii |
description | sim | descrição exposta ao cliente |
command | sim | executável real |
args_prefix | não | argumentos confiáveis antes dos argumentos MCP |
targeting | não | torna a tool target-aware |
policy | não | parâmetros do Jasper |
auth | não | estratégia de sessão; padrão inherited |
environment | não | arquivo persistente; padrão .env |
Targeting Kubernetes
targeting:
mode: kubectl_context
locked_options:
- --custom-endpoint
kubectl_context injeta --context <context> para o target selecionado. Existe uma baseline não removível de flags bloqueadas:
--context --kubeconfig --cluster --user --token --server
--username --password --client-key --client-certificate
--certificate-authority --insecure-skip-tls-verify --tls-server-name
--as --as-group --as-uid --as-user-extra
Tanto --flag valor quanto --flag=valor são recusados. locked_options adiciona flags específicas do provider e cada item deve começar com --, sem espaço ou =.
Cada target possui target.yaml com version: "1":
version: "1"
name: lab
context: local-context
identity:
provider: aws
scope: lab
expect: "111122223333"
O name deve coincidir com o diretório e o context não pode ser vazio ou conter quebra de linha. O bloco identity define a autenticação:
| Campo | Obrigatório | Descrição |
|---|---|---|
provider | sim | tool de um provider instalado e não target-aware que roda o lifecycle de autenticação |
scope | não | balde de credencial em identities/<scope>; default = nome do target |
profile | não | profile a injetar (via auth.profile_env do provider de identidade) |
expect | não | identidade exigida; conferida pelo probe auth.identity do provider antes de cada execução |
O target usa o lifecycle do provider de identidade (estratégia, validação, coleta, renovação), mas isolado no balde scope: cache, credenciais e lock ficam em identities/<scope>/. Por padrão o escopo é o nome do target, então targets distintos não compartilham sessão; dar o mesmo scope a vários targets é a forma explícita de reaproveitar uma sessão. Providers inherited sem validator produzem session-unchecked.
expect só é aceito quando o provider de identidade declara auth.identity; caso contrário é erro de configuração. Se o provider indicado não estiver instalado, o Torii rejeita a criação ou o carregamento do target. Não existe fallback para outro provider.
O registry valida a referência durante o startup, mas o Jasper decide antes de o Torii ler ambiente, cache ou credenciais e antes de executar o lifecycle do provider indicado. Somente em uma chamada permitida, esse lifecycle executa sua validação, coleta ou renovação. O .env persistente e o ambiente de sessão desse provider são aplicados ao processo filho do provider alvo; não entram no ambiente global do servidor.
Um provider instalado como dependência de autenticação continua publicado como tool MCP nesta versão. Mantenha seu rules.yaml em default deny quando o agente não precisar invocá-lo diretamente.
Targeting AWS por profile
targeting:
mode: aws_profile
Esse modo requer auth.strategy: inherited. O target.yaml fixa um profile humano e a conta esperada no bloco identity:
version: "1"
name: producao
region: sa-east-1
identity:
provider: aws_profile
scope: empresa-producao
profile: empresa-producao
expect: "111122223333"
identity.profile não pode ser vazio ou conter quebra de linha; identity.expect deve conter exatamente 12 dígitos ASCII; region, quando presente, também não pode ser vazio ou conter quebra de linha. context não é aceito nesse modo. identity.provider deve ser a própria tool target-aware, como aws_profile; ele expressa que o binding autentica pelo próprio lifecycle. O escopo padrão criado por torii target add --profile é o nome do profile, de modo que targets do mesmo profile compartilham sessão e profiles distintos ficam isolados.
O Torii injeta --profile <profile> (e AWS_PROFILE, via auth.profile_env) e, quando configurada, --region <region>. O agente não pode enviar --profile, --region, --endpoint-url, --no-sign-request, --ca-bundle ou --no-verify-ssl, nas formas separada ou --opção=valor. Antes de executar o argumento solicitado, toda chamada permitida roda o probe auth.identity (sts get-caller-identity, campo Account) e exige a conta esperada. Profile, conta e região não entram no schema MCP nem nos resultados; somente o alias aparece.
Cache, lock e diretório auth/ desse modo pertencem ao balde identities/<scope> do provider. torii reauth não altera profiles: a autenticação é feita pelo humano com o fluxo nativo do AWS CLI e a chamada é repetida depois.
Ativação temporária de targets
target.yaml configura um alias, mas não o torna utilizável pelo agente. Todo target-aware começa sem lease. O lease é estado operacional por provider, fora do schema do provider e do target, e é criado somente pelo control plane humano:
torii target activate <tool> <name> [--for <minutes>] [--add]
O estado vincula o alias a um digest do target.yaml e a uma expiração. Portanto, editar um binding invalida autorizações anteriores. A duração é de 1 a 1.440 minutos; sem --for, usa default_target_minutes (15). A ativação padrão substitui todos os aliases ativos da tool; --add conserva os existentes e permite que o agente escolha qualquer alias ativo em operações permitidas. Todos os aliases continuam no enum MCP, ativos ou não. Veja Layout de configuração para o arquivo de estado e CLI para revogação e status.
O lease não é uma regra accept, não é grant e não dispensa a autenticação. O dispatcher verifica deny explícito antes de pedir o lease e o verifica novamente antes de ambiente/autenticação e do launch.
Política
policy:
minimum_accept_tokens: 2
minimum_accept_tokens vale somente para accept em rules.yaml. O escopo de um grant temporário é escolhido pelo operador na janela de autorização como invocação exata ou prefixo de tokens; não é derivado automaticamente pelo provider. Em providers target-aware, targets/<name>/rules.yaml substitui o rules.yaml compartilhado quando existe. Um grant só é consultado depois de o alias possuir lease válido; ele não ativa target algum.
forbidden_args
policy:
forbidden_args:
- "-f"
- "--filename"
- "-i"
- "--stdin"
Argumentos negados em qualquer posição do argv, antes de qualquer regra ser avaliada. Servem para fechar canais que a política não consegue inspecionar — uma query lida de arquivo ou de stdin em vez de vir no próprio argv. Uma chamada com um argumento proibido é negada com fonte forbidden-arg e nunca executada. O casamento aceita a forma nua (--filename) e a forma --filename=valor.
ignore_args
policy:
ignore_args:
leading: 0
flags:
- "--format"
- "-o"
Normalização do argv aplicada somente à avaliação da política — nunca ao comando executado. Remove ruído que poderia acionar uma regra por engano: leading descarta N tokens iniciais (ex.: um subcomando fixo) e flags descarta flags de formatação. Uma flag nua também descarta o token de valor seguinte (--format json); a forma --format=json descarta só o token único. Se um regex compilar de forma inválida, a avaliação falha fechada (erro, nunca allow silencioso).
Pacotes antigos podem conter policy.grant_rule. O campo é aceito apenas por compatibilidade e não influencia grants novos.
Autenticação environment
auth:
strategy: environment
fields:
- name: TOKEN
label: Session token
secret: true
required: true
inject:
environment:
CLI_TOKEN: "${TOKEN}"
validate:
command: cli
args: [whoami]
cache_ttl_seconds: 300
Cada template deve ser exatamente ${NOME} e referenciar um field declarado. validate é opcional, mas recomendado para credenciais coletadas.
Autenticação inherited
auth:
strategy: inherited
validate:
command: cli
args: [account, show]
Torii não coleta material nessa estratégia. session_command e credential_file são reconhecidas e ainda não implementadas.
Sem validate, uma sessão inherited é registrada como session-unchecked e não recebe cache de validade. Com validate, o Torii não consegue renovar a sessão (o login é externo, via SSO/profile): torii reauth aponta o humano para o fluxo nativo.
Verificação de identidade e injeção de profile
Um provider que serve de identidade para targets pode declarar campos extras em auth:
auth:
strategy: inherited
identity:
command: aws
args: [sts, get-caller-identity]
field: Account
cache_ttl_seconds: 300
profile_env: AWS_PROFILE
removed_env:
- AWS_ACCESS_KEY_ID
- AWS_SESSION_TOKEN
- AWS_PROFILE
auth.identityé o probe que responde “de quem é esta sessão?”. Roda sob o comando do próprio provider (não sob o comando alvo), força saída JSON e lê o campofield. Um target comidentity.expectcompara o resultado antes de executar; o resultado é cacheado por escopo em.identity-cache. Sem esse probe,expecté recusado na configuração.auth.profile_envé a variável que carrega oidentity.profiledo target — por exemploAWS_PROFILE, para que o plugin de credencial exec do kubectl herde o profile.auth.removed_envlista variáveis de ambiente que nunca podem vazar do processo servidor para uma invocação autenticada por este provider; as credenciais/profile injetados vencem qualquer valor ambiente.
environment.file deve ser relativo e permanecer dentro do diretório do provider.
Pacotes e catálogo de providers
Um pacote de provider é declarativo: YAML, ambiente inicial e setups de política. Ele não pode conter nem executar scripts de instalação ou binários.
Estrutura
aws/
├── manifest.yaml
├── provider.yaml
├── rules.yaml
├── env.example
└── setups/
└── readonly/
└── rules.yaml
O rules.yaml da raiz é obrigatório e deve ter accept e deny vazios. O instalador recusa o pacote inteiro se essa condição não for satisfeita.
version: "1"
name: aws
package_version: "0.1.0"
description: AWS CLI com autenticação temporária.
provider: provider.yaml
rules: rules.yaml
environment: env.example
setups:
- name: readonly
kind: readonly
description: Descoberta e leitura operacional comum.
rules: setups/readonly/rules.yaml
Podem existir vários setups, mas o único kind implementado é readonly. O Torii valida estrutura e regras mínimas; a afirmação de que uma operação é realmente read-only depende da revisão do pacote e do CLI real.
Fontes de instalação
torii provider install ./provider
torii provider install ./provider.zip
torii provider install ./provider.tar
torii provider install ./provider.tar.gz
torii provider install https://example.org/provider.zip
torii provider install aws
A resolução tenta path existente, URL HTTPS e, por último, nome no catálogo canônico. Archives ZIP, TAR e TAR.GZ/TGZ são aceitos. Extração limita tamanho e quantidade de arquivos e rejeita traversal, symlinks, hardlinks e arquivos especiais.
Catálogo
O catálogo é um index.yaml:
version: "1"
providers:
- name: aws
version: "0.1.0"
description: Provider oficial AWS.
source: releases/aws-0.1.0.zip
sha256: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
torii provider search [query] lê por padrão https://raw.githubusercontent.com/torii-mcp/torii-canon-providers/main/index.yaml. Artefatos remotos exigem HTTPS e o SHA-256 do catálogo é conferido antes da extração. TORII_PROVIDER_CATALOG substitui o catálogo oficial por um path local ou URL HTTPS.
No catálogo oficial, source aponta para um asset ZIP de uma GitHub Release do repositório de providers. O fluxo de provider install aws, por exemplo, é:
- baixar o
index.yamlcanônico; - localizar a entrada cujo
nameéaws; - resolver e baixar a URL HTTPS declarada em
source; - comparar o SHA-256 do conteúdo com o valor do índice;
- extrair em diretório temporário e validar manifest, provider, regras vazias e setups;
- instalar o provider e registrar origem, versão e hash em
.torii-package/lock.yaml.
O pacote é independente de Windows ou Linux porque contém apenas arquivos declarativos. O executável indicado por provider.yaml, como aws ou kubectl, continua sendo uma dependência externa instalada pelo usuário na plataforma.
command recebe o nome nu do CLI, sem extensão e sem caminho. No Windows, o Torii procura esse nome no PATH combinando cada diretório com as extensões do PATHEXT, então um CLI distribuído como wrapper batch é encontrado sem variante por sistema: command: az resolve para az.cmd, que é o único executável que a Azure CLI instala. Ver “Resolução do executável” no modelo de segurança.
Estado instalado
providers/aws/
├── provider.yaml # gerenciado pelo pacote
├── rules.yaml # propriedade do usuário
├── .env # propriedade do usuário
├── .torii-package/ # manifest, lock e setups instalados
├── grants
└── auth/
install cria rules vazio. setup é o único comando que escreve nele e só trabalha sobre uma política vazia. upgrade substitui apenas provider.yaml e .torii-package/; não abre rules, ambiente ou estado operacional para escrita.
API MCP
Torii usa MCP por stdio e anuncia a capability de tools. Cada provider carregado aparece exatamente uma vez, além da tool fixa e somente de leitura torii_policy.
Consulta de política
Antes de escolher uma operação, o agente pode consultar as regras ativas sem executar provider, ler ambiente, cache ou credenciais:
{
"name": "torii_policy",
"arguments": { "provider": "aws" }
}
Para uma tool target-aware, informe o alias anunciado:
{
"name": "torii_policy",
"arguments": { "provider": "kubectl", "target": "mpce_dev" }
}
A resposta contém accept, deny, minimum_accept_tokens e ignored_accept. Quando existir targets/<alias>/rules.yaml, ela é a política devolvida, pois substitui a regra compartilhada. unmatched explica que comandos fora dessas listas continuam em default deny, salvo aprovação humana ou grant temporário ativo. A consulta não mostra credenciais, ambiente, grants ou leases e não modifica estado; ela funciona mesmo quando o alias está inativo.
Provider simples
Uma tool como aws exige apenas o vetor de argumentos:
{
"type": "object",
"required": ["args"],
"properties": {
"args": { "type": "array", "items": { "type": "string" }, "minItems": 1 }
},
"additionalProperties": false
}
Chamada:
{
"name": "aws",
"arguments": { "args": ["s3", "ls"] }
}
Provider target-aware
Uma tool como kubectl ou aws_profile exige também target. O enum é construído com todos os aliases carregados no startup, ativos ou inativos:
{
"type": "object",
"required": ["target", "args"],
"properties": {
"target": { "type": "string", "enum": ["mpce_dev"] },
"args": { "type": "array", "items": { "type": "string" }, "minItems": 1 }
},
"additionalProperties": false
}
Sem targets cadastrados, o schema torna target impossível de satisfazer até o humano criar um alias e reiniciar o servidor. Criar um alias não o ativa; o lease é avaliado pelo dispatcher, não pelo schema.
Chamada:
{
"name": "kubectl",
"arguments": {
"target": "mpce_dev",
"args": ["get", "pods", "-n", "agente-rm"]
}
}
Campos extras, args ausente ou vazio, target ausente/desconhecido e itens não string são recusados. Tool desconhecida também é erro de parâmetros.
Para um alias conhecido, mas sem lease válido, o dispatcher mostra ao humano o binding solicitado e os aliases ativos. O humano pode substituir os ativos pelo solicitado, adicioná-lo conscientemente ao conjunto ou negar. Em headless, a decisão é negação. O prompt acontece depois de um deny explícito ser descartado e antes de grants Jasper, ambiente, autenticação ou execução. O agente não recebe uma tool para ativar, limpar ou consultar leases.
Em aws_profile, o enum contém apenas aliases humanos. O profile AWS, a conta esperada e a região configurados no alias nunca são campos MCP. Se a identidade do profile estiver indisponível ou pertencer a outra conta, a resposta de erro pede intervenção humana sem revelar esses valores.
Resposta
{
"provider": "kubectl",
"target": "mpce_dev",
"decision": {
"result": "allow",
"source": "rules",
"rule": "get pods"
},
"execution": {
"exit_code": 0,
"stdout": "...",
"stderr": "",
"truncated": false
}
}
target é omitido para providers simples. execution é omitido quando a decisão nega a chamada. Falhas operacionais são devolvidas como tool result estruturado com isError; um exit code não zero do CLI continua sendo um resultado normal de execução.
Lifecycle
Não há tool de shutdown, reauth, edição, ativação ou limpeza de targets. O cliente controla o processo; o humano usa a CLI de controle fora do MCP. Em uma chamada autorizada cuja sessão gerenciada não está disponível, o Torii solicita a autenticação humana automaticamente. A renovação proativa continua sendo torii reauth <provider-tool> [target] somente para autenticação gerenciada. Para aws_profile, o agente pede que o humano autentique o profile já configurado pelo fluxo nativo AWS e repete o mesmo alias; ele não pode trocar o profile.
CLI de controle
Esta CLI pertence ao humano e nunca é publicada como tools MCP.
Todos os níveis aceitam --help ou -h; torii help <comando> e a forma em camadas torii provider help install são equivalentes. Por exemplo:
torii --help
torii reauth --help
torii provider --help
torii provider install --help
| Comando | Efeito |
|---|---|
torii | inicia o servidor MCP stdio |
torii --version ou torii -V | imprime a versão do binário |
torii init | cria raiz e settings, sem instalar providers |
torii config-dir | imprime o diretório de configuração |
torii self upgrade [--check] | troca o próprio binário pela última release |
torii provider list | lista providers locais, versão e origem |
torii provider search [query] | pesquisa o catálogo configurado |
torii provider install <source> | instala nome, diretório, archive ou URL HTTPS |
torii provider setup <provider> <setup> | aplica setup read-only sobre rules vazio |
torii provider upgrade <provider> | troca somente arquivos gerenciados pelo pacote |
torii policy show <tool> [target] | imprime a política ativa e avisa sobre accepts ignorados |
torii policy edit <tool> [target] [--create] | abre a política no editor, valida e só então substitui |
torii reauth <tool> [target] | força autenticação gerenciada no escopo |
torii target add <tool> <name> --context <context> --provider <tool> [--scope <scope>] [--expect <identity>] | valida o context e cria o target autenticado pelo provider de identidade indicado; --scope isola o balde de credencial (default: nome do target) e --expect fixa a identidade conferida pelo probe |
torii target add <tool> <name> --profile <profile> --account-id <12-dígitos> [--region <região>] | cria um alias aws_profile com profile e conta esperada sob controle humano |
torii target list <tool> | lista aliases e seus bindings fixos no control plane humano |
torii target show <tool> <name> | imprime target.yaml |
torii target activate <tool> <name> [--for <minutes>] [--add] | concede lease temporário ao alias; por padrão substitui todos os aliases ativos da tool |
torii target status <tool> | mostra o estado dos leases e suas expirações |
torii target clear <tool> | revoga todos os leases da tool, sem alterar o estado operacional |
torii target remove <tool> <name> --force | revoga o lease e remove o target e seu estado isolado |
torii agent list | lista adapters de agentes implementados |
torii agent install <agent> [--hook] [--yes] | registra o MCP no cliente e, quando ele oferecer hook, instala o guard |
torii agent status <agent> | mostra o estado MCP/hook e sua propriedade |
torii agent uninstall <agent> [--hook] | remove toda a integração ou somente o hook |
Install recusa destino existente. Setup recusa rules não vazio. Upgrade requer lock de pacote e preserva rules, .env, grants, targets, cache e autenticação. Alterações no conjunto/configuração de providers exigem reiniciar o MCP.
update e upgrade
O Torii usa upgrade para trocar a versão de algo instalado — provider upgrade para um pacote, self upgrade para o próprio binário. Não existe update em lugar nenhum, e isso é deliberado: na convenção que ferramentas como apt e brew firmaram, update sincroniza um índice local antes de decidir, e upgrade troca o que está instalado. O Torii não mantém índice local — provider search e provider install leem o catálogo na hora, a cada chamada — então não há o que atualizar, só o que trocar de versão. Usar os dois verbos para a mesma ação obrigaria a decorar qual vale para quê.
Quem digitar o nome antigo recebe a correção em vez de um erro genérico:
there is no `torii provider update`; changing an installed version is `torii provider upgrade`
self upgrade é humano e explícito: nada no Torii se atualiza sozinho, e o MCP não expõe essa ação. Ele resolve a última release da plataforma pelo redirecionamento de /releases/latest, confere o SHA-256 publicado e substitui o binário em execução; providers, políticas, targets, grants e credenciais ficam intactos. --check apenas informa. Um cliente MCP já em execução continua com o binário anterior até ser reiniciado.
policy edit abre uma cópia da política no $VISUAL ou $EDITOR — notepad no Windows e vi nos demais sistemas quando nenhum está definido. Um editor que devolve o controle imediatamente precisa ser instruído a esperar, como code --wait ou subl -w. Ao fechar, o rascunho é parseado e cada regra é compilada; só depois disso ele substitui o arquivo vivo de forma atômica. YAML malformado, regex inválido ou política vazia não chegam ao arquivo ativo, e o rascunho recusado é preservado num caminho informado no erro. Em terminal interativo, o Torii oferece reabrir o editor. Sem alterações, nada é gravado. Como rules.yaml é relido em cada chamada, não é preciso reiniciar o MCP.
policy edit <tool> <target> exige um alias já configurado. Se aquele alias ainda não tiver política própria, ele herda a compartilhada, e criar uma exige --create — porque a política do target substitui a do provider naquele alias em vez de somar. policy show aceita os mesmos escopos e avisa quando um accept fica abaixo de minimum_accept_tokens e, por isso, é ignorado na avaliação.
O provider informado em --provider é o provider de identidade (identity.provider): precisa estar instalado e não pode exigir target. Cada target autentica no balde identities/<scope> desse provider — por padrão um balde por target, então targets distintos não compartilham sessão; use --scope para compartilhar de propósito. --expect só é aceito se o provider de identidade declarar auth.identity. torii reauth <tool-alvo> <target> delega ao lifecycle desse provider no escopo do target. Se ele usar inherited sem validator, não há material renovável pelo Torii; com validator (SSO/profile externo), o reauth aponta para o fluxo nativo.
Para aws_profile, use target add sem --provider: o Torii grava a própria tool no binding e isola cache e lock por alias. target list aws_profile mostra alias, profile e conta esperada somente no control plane humano. torii reauth aws_profile <alias> não troca a sessão; autentique o profile configurado pelo AWS CLI e repita a chamada.
Todo target-aware nasce inativo, embora continue anunciado no schema MCP. target activate é um comando exclusivamente humano: --for aceita de 1 a 1.440 minutos e, se omitido, usa default_target_minutes (15 por padrão). Sem --add, a ativação substitui todos os leases ativos daquela tool. --add preserva os demais aliases e deve ser usado somente com a compreensão de que o agente poderá escolher qualquer alias ativo em operações permitidas. target status não altera estado.
target clear grava um conjunto vazio de leases e invalida decisões de janelas antigas; ele não apaga target.yaml, rules, grants Jasper, .env, credenciais, cache ou configuração de provider. Tampouco encerra um processo já iniciado, embora bloqueie launches futuros que ainda precisem passar pela conferência de lease.
Não existem torii aws s3 ls, torii kubectl get pods, instalação via MCP ou atualização automática. Durante o servidor MCP, stdout é reservado; subcomandos humanos usam stdout para dados e stderr para progresso. reauth é exclusivamente humano; uma chamada MCP já autorizada abre autenticação humana automaticamente quando a sessão gerenciada não está disponível.
<agent> aceita codex, claude, gemini, cursor, antigravity, opencode, copilot, copilot-cli ou pi; torii agent list mostra o que cada um suporta. opencode, copilot, copilot-cli e pi não oferecem hook, então --hook é recusado antes de qualquer escrita e o status informa hook not supported. O pi não fala MCP nativamente: sua configuração só é lida por uma extensão MCP instalada pelo humano, então a instalação avisa e exige confirmação interativa ou --yes. agent install é control plane humano: escreve na configuração global do cliente, preserva entradas existentes e recusa substituir um servidor MCP torii conflitante. O estado necessário para remover somente conteúdo gerenciado fica em <TORII_CONFIG_DIR>/agents/<agent>.json.
Auditoria
O arquivo global torii.log registra eventos em formato separado por |:
epoch | escopo | evento | regra-curta | detalhe-opcional
Exemplo:
1784000000 | aws | allowed-by-rules | ec2 describe-instances
1784000001 | aws | session-ok | -
1784000002 | aws | ran | ec2 describe-instances | exit=0
1784000003 | kubectl/mpce_dev | ran | get pods | exit=0
Providers simples usam seu nome como escopo. Providers target-aware usam provider/target, o que permite distinguir decisões e sessões sem registrar o context real.
Eventos comuns
invoke;allowed-by-ruleseallowed-by-grant;denied-explicitedenied-interface;override-onceeoverride-timed;invalid-accept;session-ok,session-unchecked,session-invalid,session-refreshedesession-candidate-invalid;preflight-provider,preflight-okepreflight-failed;identity-ok,identity-mismatcheidentity-check-failed;target-access-requested,target-access-denied,target-access-replaced,target-access-added,target-access-stale,target-access-lost,target-access-revokedetarget-access-cleared;reauth-forced;rancom exit code.
Sanitização
Quebras de linha e | são substituídos. A referência de chamada é limitada aos dois primeiros argumentos para evitar registrar a linha completa. O log não contém credenciais, clipboard, stdout ou stderr.
Eventos de preflight registram somente a tool do provider autenticador. Seus argumentos, ambiente e saída não são registrados.
Eventos identity-* registram somente o escopo de auditoria e o resultado da conferência. Identidade esperada, identidade observada e saída do probe não entram no log; elas viajam apenas no erro devolvido à chamada.
Eventos target-access-* registram somente o alias ou - na regra curta. O detalhe contém duração, contagem de aliases ou um rótulo estático de fase/resultado — por exemplo, before-environment, after-authentication, at-launch, retry-required, already-active, target-removed ou all — nunca binding, profile, conta, context, argumentos completos ou conteúdo do arquivo de leases. target-access-stale indica que o estado mudou enquanto a janela estava aberta: a escolha antiga não é aplicada; se o alias já estiver ativo no novo estado a chamada pode continuar, caso contrário é negada e requer nova tentativa. target-access-lost indica expiração ou revogação em uma das rechecagens antes de ambiente, autenticação ou launch. target-access-revoked registra a revogação preventiva do lease quando o control plane remove um target.
A escrita é best-effort: uma falha de auditoria não interrompe a operação. Portanto, este arquivo é observabilidade local, não ledger inviolável ou mecanismo de compliance por si só.
Proteção
Proteja torii.log com as permissões do diretório de configuração. Embora ele não deva conter segredos, revela providers, ações tentadas e horários operacionais.
Migração do AWS Gate
O Torii não migra configuração do AWS Gate automaticamente.
Executar torii, torii init, comandos de provider ou comandos de integração de agentes não lê nem copia ~/.config/.awsgate. As variáveis AWSGATE_CONFIG_DIR e AWSGATE_NO_GUI também não são aliases do Torii.
Essa separação permite manter o AWS Gate em uso enquanto o Torii é desenvolvido e homologado. Os dois programas têm diretórios, regras, credenciais, grants, caches e logs independentes.
Migração futura
Não existe comando de migração nesta versão. Quando esse fluxo for implementado, ele deve ser explícito, mostrar origem e destino, não alterar a origem e pedir confirmação antes de copiar regras ou credenciais.
Até lá, configure o Torii separadamente em ~/.config/torii ou use TORII_CONFIG_DIR para um ambiente isolado de desenvolvimento.
Solução de problemas
no providers installed
O registry não encontrou provider.yaml sob providers/. Execute torii provider list, instale um pacote, confirme TORII_CONFIG_DIR e use torii config-dir para verificar a raiz efetiva. torii init sozinho não instala providers.
rules file not found
O provider existe, mas não possui rules.yaml. Crie uma política explícita; não há fallback permissivo.
could not find the executable ... in PATH
O CLI do provider não está no PATH do processo que iniciou o Torii. Confirme com where <cli> no mesmo terminal e reinicie o cliente MCP depois de alterar o PATH, pois o servidor herda o ambiente de quem o lançou. No Windows não é preciso indicar extensão em command: o nome nu é procurado com as extensões do PATHEXT, então command: az encontra az.cmd. A busca ignora o diretório atual por segurança; um CLI que só exista ali não é executado.
Chamada não resolvida é negada sem janela
Verifique TORII_NO_GUI. Qualquer valor não vazio diferente de 0 desabilita GUI. Em headless, default deny é o comportamento esperado. Variáveis do AWS Gate não alteram o Torii.
Sessão AWS não renova
Confirme que aws está no PATH, que as três variáveis foram preenchidas e que aws sts get-caller-identity funciona com a mesma rede. Torii suprime stdout/stderr do comando de validação para não vazar detalhes; use o AWS CLI diretamente como humano para diagnóstico.
Alias aws_profile pede autenticação humana ou informa conta divergente
O Torii não revela o profile ou os números de conta ao agente e não tenta trocar a sessão. No terminal humano, autentique o profile configurado no alias pelo mecanismo correspondente, por exemplo aws sso login --profile empresa-producao, e confirme aws sts get-caller-identity --profile empresa-producao. Depois repita a chamada MCP com o mesmo alias. Revise torii target show aws_profile <alias> se a conta esperada mudou.
Alias target-aware inativo ou negado em headless
Criar um alias não cria seu lease. Confirme torii target status <tool> e ative explicitamente com torii target activate <tool> <alias> --for 30. A duração permitida vai de 1 a 1.440 minutos; sem --for, usa default_target_minutes. Em TORII_NO_GUI=1, uma chamada a alias inativo é negada por segurança, pois não há humano para aprovar o binding.
Muitos aliases ativos
target activate <tool> <alias> substitui os ativos por padrão. Se alguém usou --add, o agente pode escolher qualquer alias ainda ativo em operações permitidas. Inspecione torii target status <tool> e use torii target clear <tool> ou uma nova ativação sem --add para reduzir o conjunto. Clear não apaga grants, credenciais, cache ou configuração e não mata processos já em execução.
Estado de leases inválido
Um .target-authorizations.yaml corrompido falha fechado: nenhuma chamada target-aware prossegue. Use torii target clear <tool> para regravar atomicamente um conjunto vazio válido; o comando não precisa desserializar o estado anterior e não altera grants, credenciais, cache ou targets.
inherited authentication cannot be renewed
O provider não possui coleta gerenciada. Renove a sessão pelo CLI humano ou pelo credential store correspondente e reinicie/aguarde expirar o cache conforme necessário.
Saída truncada
execution.truncated: true indica que stdout e/ou stderr excederam max_output_bytes. Aumente o limite com cautela ou restrinja a consulta no provider.
dlltool.exe ou as.exe ausente
No Windows GNU, coloque uma distribuição MinGW-w64 completa no PATH durante build/test.
Cliente MCP não inicializa
- execute o binário diretamente e verifique erros em stderr;
- confirme que nenhum wrapper escreve banner no stdout;
- valide o path absoluto e
TORII_CONFIG_DIRna configuração do cliente; - use
torii provider listfora da sessão MCP para testar o registry.
Arquitetura do código
O entrypoint src/main.rs delega a app, que separa prompt interno, control plane e servidor MCP.
src/
├── app.rs startup e CLI de controle
├── targets.rs control plane de targets
├── policy.rs edição humana validada das políticas
├── self_upgrade.rs troca verificada do próprio binário
├── agents/codex.rs integração Codex e guard compartilhado de shell
├── agents/portable.rs adapters JSON: Claude, Gemini, Cursor, Antigravity, opencode, Copilot e pi
├── mcp/server.rs protocolo e tools dinâmicas
├── core/invoke.rs orquestração de uma chamada
├── target_access.rs leases temporários de aliases target-aware
├── jasper/ regras e grants
├── providers/
│ ├── config.rs schema YAML
│ ├── registry.rs descoberta de providers/targets
│ ├── packages.rs manifest, fontes, catálogo e lifecycle de pacotes
│ └── auth/session.rs lifecycle de sessão
├── runtime/exec.rs processos filhos
├── control/gui.rs janelas em subprocesso
├── config/ paths, settings e env
├── audit.rs log sanitizado
└── error.rs erros públicos seguros
Dependências entre camadas
mcp chama core; core chama Jasper, lease de target, sessão, control e runtime. Jasper permanece puro em relação a processo e autenticação. Runtime não decide política. Providers descrevem mecanismo, não operações permitidas. Depois de deny explícito e antes de grants ou sessão, core exige lease válido para aliases target-aware; ele o relê antes de ambiente/autenticação e antes do runner. Depois de allow, um target kubectl_context pode delegar autenticação ao lifecycle de outro provider não target-aware; o ambiente retornado é composto somente para o processo filho alvo. Um target aws_profile usa seu próprio escopo, fixa o profile e confere a conta via STS antes do runner.
GUI em subprocesso
O servidor usa stdout para MCP, então prompts são abertos por uma nova execução do próprio binário com o subcomando interno __prompt. Pedido e resposta usam JSON pelos pipes privados. Durante autenticação, uma thread de background do subprocesso da GUI executa o validator sem bloquear o repaint; somente uma candidata validada retorna ao processo pai para persistência. Stderr do prompt é suprimido.
Estado compartilhado
ProviderRegistry guarda providers e targets em Arc, com mutex assíncrono por provider e, quando necessário, por target. Settings, providers e targets são carregados no startup. O campo provider de cada target é validado depois que todo o registry é montado. kubectl_context herda cache e lock do lifecycle indicado; aws_profile os mantém no próprio target. Leases ficam em um arquivo por provider, com digest de binding, revisão, arquivo de lock exclusivo do sistema operacional e escrita atômica; o handle do lock é liberado pelo sistema ao término do processo, sem TTL ou limpeza por timeout de lock stale. Eles são relidos durante chamadas. Regras e grants também são lidos durante chamadas.
Onde adicionar comportamento
- nova semântica de política:
jasper/, com testes de token boundary; - nova estratégia de auth comprovada:
providers/auth/, preservando transação e lock; - campo público de provider:
providers/config.rs, registry, exemplos e docs; - mudança MCP:
mcp/server.rsereference/mcp-api.md; - novo controle humano:
app.rs/targets.rs/control/, nunca como tool de agente. - mudança em integração de agente:
agents/,guides/agents.mdereference/cli.md.
Testes e qualidade
Antes de entregar uma mudança:
cargo fmt --all -- --check
cargo check --all-targets
cargo test --all-targets
cargo clippy --all-targets -- -D warnings
mdbook build docs
Testes existentes
Testes unitários cobrem parsing de ambiente, matching, grants, pacotes em diretório/archive, setup, upgrade preservando estado e truncamento UTF-8. tests/security_flow.rs prova que deny explícito e default deny headless encerram antes de ambiente, autenticação ou executável. tests/mcp_readonly_integration.rs negocia MCP com um processo Torii real, executa uma operação local de leitura permitida e confirma que outra leitura explicitamente negada não inicia o provider.
Regressões prioritárias
Toda mudança no fluxo deve preservar testes para:
- deny vencendo accept;
s3não casando coms3api;- grant
exactrecusando argumento acrescentado, removido ou alterado; - grant
prefixpermitindo somente as variações após a fronteira escolhida; - credenciais não carregadas no caminho negado;
- argumentos encaminhados sem shell;
- exit code e streams preservados;
- reauth inválido mantendo sessão antiga;
- concorrência abrindo uma única coleta por escopo;
- target obrigatório, desconhecido e flags de override recusadas antes de env/auth;
- alias
aws_profilemantendo profile e conta fora do schema MCP, removendo overrides e interrompendo antes do comando quando a identidade não confere; - target-aware inativo por padrão, embora todos os aliases permaneçam no enum MCP;
- deny explícito em target inativo sem prompt de lease, grant, ambiente, autenticação ou processo;
- lease ativo antes de grants/env/auth, expiração e revogação bloqueando a chamada nas rechecagens antes de sessão e launch;
Replace,Add,Deny, limites de 1 a 1.440 minutos, headless deny e CAS rejeitando uma decisão de janela obsoleta;- digest de binding invalidando lease após editar, remover ou recriar um alias;
target clearpreservando grants,.env, cache, credenciais,target.yamle processos já iniciados;- múltiplos aliases ativos permanecendo no schema; na janela, o alerta ocupa a largura disponível junto às ações e Adicionar só conclui depois de 1 segundo de pressão contínua, reiniciando ao soltar; o clique que traz uma janela sem foco para frente já inicia a contagem;
- limite combinado de saída;
- tools/list contendo uma tool por provider e nenhuma tool de controle.
- pacote recusando rules base não vazio, setup recusando overwrite e upgrade preservando rules/estado.
Testar documentação
mdbook build docs valida SUMMARY.md, capítulos ausentes e links processados pelo preprocessor padrão. Blocos Rust meramente ilustrativos devem usar rust,ignore; exemplos compiláveis podem ser exercitados com mdbook test docs quando não dependerem do crate interno.
Headless
Defina TORII_NO_GUI=1 em automação. Não tente automatizar cliques em janelas como substituto para testes das regras e do lifecycle.
Catálogo de homologação live
Este documento define os casos de homologação humana do Torii. Ele é o catálogo estável; cada sessão real produz um arquivo de evidência separado em tests/live/runs/YYYY-MM-DD.md.
O catálogo precisa ser aprovado antes da primeira execução oficial. Uma execução exploratória não conta como evidência.
Contrato da homologação
- Toda operação enviada a AWS ou Kubernetes deve ser estritamente de leitura.
- Cada caso começa em uma raiz nova
TORII_CONFIG_DIRcom prefixotorii-live-<caso>-sob o diretório temporário do sistema. - Instalam-se somente o provider alvo e, para testes com target, o provider estritamente necessário indicado no campo
provider. Não se aplica nenhum setup de política. - O
rules.yamlcomeça vazio e recebe somente as regras indispensáveis para aquele caso. - Antes de executar, o agente mostra no chat o conteúdo integral de cada arquivo de regras que será usado e aguarda aprovação explícita do operador.
- Depois da aprovação, o agente informa os tokens da invocação e a ação humana exata: Negar, ou escolher Temporariamente, revisar/restaurar a sugestão estrutural ou selecionar
Exact, definir a duração, marcar a confirmação de revisão e clicar Permitir. - O agente confere resposta MCP, arquivos locais permitidos e eventos sanitizados de
torii.log. - Credenciais, conteúdo de
auth/credentials.env, clipboard e stdout/stderr completos não entram na evidência. - Depois de registrar a evidência, o agente remove somente a raiz daquele caso, após validar que o caminho continua dentro do diretório temporário e possui o prefixo esperado.
- Casos com múltiplas invocações preservam a mesma raiz até terminar todas as repetições. Isso se aplica a
allow once, grant temporário, expiração, reautenticação transacional, leases e isolamento entre targets. - Diante de qualquer tentativa de escrita remota, context produtivo, regra extra ou divergência entre o plano aprovado e o ambiente preparado, o caso para antes da chamada.
- Os contexts reais dos casos Kubernetes são escolhidos somente no ambiente local e nunca entram no catálogo, evidência, resposta MCP ou auditoria. O target de referência é publicado apenas como
lab;K8S-AUTH-01usa um segundo target não produtivo sob o aliaslab-noaccess, com a mesma identidade válida do target de referência.
Escritas locais dentro da raiz isolada são esperadas: configuração, target, auditoria, cache, grants e sessão. Nenhum caso cria, altera ou remove recurso remoto.
Quando a janela de autorização pode aparecer
A janela de autorização existe somente para uma decisão unresolved: a chamada não casou com deny, não casou com accept e não possui grant ativo.
- match em
deny: encerra imediatamente comoexplicit-deny; não abre janela de autorização nem de autenticação e não inicia o provider; - match em
accept: segue comoallowed-by-rules, sem janela de autorização; uma janela de autenticação ainda pode aparecer depois, caso a sessão do provider precise ser criada ou renovada; - sem match em
denyouaccept, mas com grant ativo: segue comoallowed-by-grant, sem janela; - sem regra e sem grant: abre a janela de autorização; em headless, assume Negar sem abrir GUI.
Portanto, qualquer janela exibida em um caso com deny explícito torna a instância FAIL, mesmo que o operador clique Negar e nenhum subprocesso seja iniciado.
Gate obrigatório antes de cada caso
O agente apresenta um bloco com esta forma:
Caso: <ID e nome>
Raiz isolada: <caminho>
Provider/target: <tool e alias>
Lease de target: <inativo | comando de ativação, duração e aliases ativos>
Operações remotas: <lista completa; todas read-only>
Arquivos de regras: <conteúdo integral>
Invocações previstas: <quantidade e ordem>
Ações humanas: <cliques ou preenchimento esperado>
Eventos esperados: <eventos de auditoria>
Cleanup: <o que será removido>
Nenhuma invocação começa enquanto o operador não aprovar esse bloco. Alterar regra, comando, target ou sequência invalida a aprovação e exige um novo gate.
Leases em casos target-aware
Todo alias target-aware começa inativo, embora continue no schema MCP. Nos casos que precisam chegar a Jasper, ambiente, autenticação ou execução, o preparo ativa explicitamente o alias pelo control plane, por exemplo:
torii target activate kubectl lab --for 30
O gate registra duração, aliases ativos e a consequência de qualquer --add: durante a janela, o agente poderá escolher qualquer alias ativo. Casos que provam deny explícito, target ausente/desconhecido ou flag bloqueada mantêm o alias inativo quando a fronteira deve encerrar antes do lease.
Qualquer homologação específica de lease verifica ainda que: todos os aliases continuam no schema; a janela reúne os ativos em uma seção compacta; Substituir deixa somente o solicitado ativo; quando Adicionar cria múltiplos ativos, o alerta ocupa a largura disponível imediatamente acima das ações e o botão mostra progresso, só concluindo após 1 segundo de pressão contínua; soltar antes reinicia a confirmação, enquanto o clique que traz a janela sem foco para frente já inicia a contagem; Negar não muda estado; target clear remove somente leases e não mata processos nem apaga grants, cache, credenciais, .env ou target.yaml; expiração, revogação ou mudança de binding impedem launch em rechecagens posteriores.
Perfis mínimos de regras
Os casos abaixo referenciam estes perfis. Na execução, o YAML correspondente é mostrado novamente no chat.
R0 — política vazia
version: "1.0"
deny: []
accept: []
RA1 — AWS aceita apenas identidade
version: "1.0"
deny: []
accept:
- "sts get-caller-identity"
RA2 — AWS nega apenas identidade
version: "1.0"
deny:
- "sts get-caller-identity"
accept: []
RA3 — AWS deny e accept concorrentes
version: "1.0"
deny:
- "sts get-caller-identity"
accept:
- "sts get-caller-identity"
RK1 — Kubernetes aceita apenas listagem de pods
version: "1.0"
deny: []
accept:
- "get pods"
RK2 — Kubernetes nega apenas leitura de configuração
version: "1.0"
deny:
- "config view"
accept: []
RK3 — Kubernetes deny e accept concorrentes
version: "1.0"
deny:
- "config view"
accept:
- "config view"
Para providers target-aware, o gate identifica separadamente o rules.yaml compartilhado e o targets/<alias>/rules.yaml. Um arquivo não mencionado deve permanecer ausente ou exatamente em R0.
Resumo dos casos
| ID | Área | Objetivo | Perfil | Interação humana |
|---|---|---|---|---|
| MCP-01 | MCP | discovery e schema das tools | R0 em ambos | nenhuma |
| AWS-AUTH-01 | autenticação | campos obrigatórios vazios | RA1 | Validar e usar; depois fechar/cancelar |
| AWS-AUTH-02 | autenticação | cancelamento sem sessão | RA1 | Cancelar |
| AWS-AUTH-03 | autenticação | candidata inválida não persiste | RA1 | credencial inválida; Validar e usar; Cancelar |
| AWS-AUTH-04 | autenticação | candidata válida é validada e usada | RA1 | credencial temporária válida; Validar e usar |
| AWS-AUTH-05 | autenticação | reauth inválido preserva sessão válida | RA1 | sessão válida; reauth inválido; Cancelar |
| AUTH-UI-01 | autenticação | layout mínimo com uma variável | RA1 em provider de teste | conferir layout; Cancelar |
| AUTH-UI-02 | autenticação | layout com quatro variáveis | RA1 em provider de teste | conferir layout; Cancelar |
| AUTHZ-UI-01 | autorização | layout normal e comando enorme | R0 | conferir estados e rolagem; Negar |
| AUTHZ-UI-02 | autorização | feedback de permitir uma vez | R0 | Permitir uma vez; Cancelar auth |
| AUTHZ-UI-03 | autorização | sugestão estrutural, expansão e feedback temporário | R0 | Temporariamente, prefixo sugerido, 2 min; Cancelar auth |
| AWS-POL-01 | Jasper | accept executa sem prompt de acesso | RA1 | autenticar se necessário |
| AWS-POL-02 | Jasper | deny explícito encerra antes de auth | RA2 | nenhuma |
| AWS-POL-03 | Jasper | deny vence accept | RA3 | nenhuma |
| AWS-POL-04 | Jasper | unresolved negado pelo humano | R0 | Negar |
| AWS-POL-05 | Jasper | allow once não persiste | R0 | Permitir uma vez; na repetição, Negar |
| AWS-POL-06 | Jasper | grant de 2 min, escopo e expiração | R0 | Temporariamente, Exact, 2 min; ao expirar, Negar |
| AWS-POL-07 | Jasper | headless mantém default deny | R0 | nenhuma |
| K8S-POL-01 | Jasper/target | accept no target selecionado | R0 compartilhado + RK1 no target | nenhuma |
| K8S-AUTH-01 | autenticação herdada | identidade válida sem acesso ao target de isolamento | R0 compartilhado + RK1 no target | nenhuma |
| K8S-POL-02 | Jasper/target | deny explícito de leitura | R0 compartilhado + RK2 no target | nenhuma |
| K8S-POL-03 | Jasper/target | deny vence accept | R0 compartilhado + RK3 no target | nenhuma |
| K8S-POL-04 | Jasper/target | unresolved negado pelo humano | R0 compartilhado e no target | Negar |
| K8S-POL-05 | Jasper/target | allow once não persiste | R0 compartilhado e no target | Permitir uma vez; na repetição, Negar |
| K8S-POL-06 | Jasper/target | grant exact, variação e expiração | R0 compartilhado e no target | Temporariamente, Exact, 2 min; negar variação e expiração |
| K8S-POL-07 | Jasper/target | grant prefix, variação e expiração | R0 compartilhado e no target | Temporariamente, prefixo get pods, 2 min; negar após expiração |
| K8S-TGT-01 | envelope | target obrigatório | R0 | nenhuma |
| K8S-TGT-02 | envelope | target desconhecido | R0 | nenhuma |
| K8S-TGT-03 | envelope | bloqueio de --context | R0 | nenhuma |
| K8S-TGT-04 | envelope | bloqueio de --kubeconfig | R0 | nenhuma |
| K8S-TGT-05 | envelope | bloqueio de --server | R0 | nenhuma |
| K8S-TGT-06 | envelope | bloqueio de --token | R0 | nenhuma |
| K8S-TGT-07 | política | regra do target substitui compartilhada | RK1 compartilhado + deny mínimo no target | nenhuma |
| K8S-TGT-08 | isolamento | grant de um alias não atravessa outro | R0 em dois targets | Temporariamente, Exact, 2 min em A; Negar em B |
Casos MCP
MCP-01 — discovery e schema
Preparo: raiz nova, providers AWS e Kubernetes instalados, um único target Kubernetes não produtivo chamado lab, ambos os arquivos compartilhados em R0 e sem arquivos de regras específicos no target.
Operação:
cargo run --example mcp_probe -- $Torii $CaseRoot list
Critérios:
- existem exatamente as tools
awsekubectl; awsexige apenasargs;kubectlexigetargeteargs;- o enum de
targetanuncia somentelab; labcontinua anunciado sem lease ativo; consulta de schema não abre GUI nem cria lease;- nenhum context real aparece no schema;
- nenhuma operação de provider ou GUI ocorre;
torii.logpermanece ausente ou sem evento de invocação.
Casos de autenticação AWS
Todos usam somente sts get-caller-identity, provider AWS e RA1. Eles não reutilizam credenciais de outro caso.
AWS-AUTH-01 — campos obrigatórios vazios
- Chamar
sts get-caller-identity. - Confirmar que a altura da janela acompanha o formulário, sem espaço vertical excessivo e com campos e botões acessíveis.
- Clicar Validar e usar sem preencher campos.
- Encerrar a janela se ela permanecer aberta; se a invocação encerrar, não repetir.
Esperado: janela compacta e legível; erro indicando os três campos obrigatórios; nenhum credentials.env, nenhum .session-cache, nenhum ran. Auditoria contém invoke, allowed-by-rules e session-invalid.
AWS-AUTH-02 — cancelar autenticação
- Chamar
sts get-caller-identity. - Clicar Cancelar.
Esperado: erro estruturado de autenticação cancelada; nenhum arquivo de sessão; nenhum ran.
AWS-AUTH-03 — candidata inválida
- Chamar
sts get-caller-identity. - Preencher valores temporários deliberadamente inválidos, sem registrá-los na evidência.
- Clicar Validar e usar.
- Confirmar que a mesma janela permanece aberta, o formulário fica bloqueado e um indicador de progresso aparece durante a validação.
- Confirmar que o indicador desaparece, o formulário é reabilitado e a mensagem de sessão recusada aparece na mesma janela; clicar Cancelar.
Esperado: comportamento visual descrito acima; session-candidate-invalid; nenhum credentials.env persistido; nenhum .session-cache; nenhum ran da operação solicitada.
AWS-AUTH-04 — candidata válida
- Chamar
sts get-caller-identity. - Preencher credenciais temporárias válidas e clicar Validar e usar.
Esperado: a janela permanece aberta com o formulário bloqueado e indicador de progresso, fechando somente depois do sucesso; o comando interno de validação passa antes da persistência; a chamada solicitada termina com exit code zero; auditoria contém session-refreshed e ran; existência, tamanho, timestamp e hash dos arquivos de sessão podem ser registrados, nunca seu conteúdo.
AWS-AUTH-05 — reauth inválido preserva sessão
- Criar uma sessão válida dentro do próprio caso e registrar hash/timestamp de
credentials.envsem abri-lo. - Executar
torii reauth awsna mesma raiz. - Informar uma candidata inválida, clicar Validar e usar, observar a recusa e clicar Cancelar.
- Conferir que hash/timestamp do arquivo anterior não mudaram.
- Chamar
sts get-caller-identitypor MCP novamente.
Esperado: reauth-forced e session-candidate-invalid; sessão anterior intacta; chamada final com exit code zero.
AUTH-UI-01 — formulário com uma variável
Usar uma cópia isolada do provider de teste com apenas um campo obrigatório e o mesmo comando read-only aceito por RA1. Abrir a autenticação, conferir que janela, barra de status e rodapé permanecem compactos e clicar Cancelar sem preencher ou validar.
Esperado: um único campo visível, sem região vazia excessiva ou scrollbar do formulário; nenhum validator, arquivo de sessão ou ran.
AUTH-UI-02 — formulário com quatro variáveis
Usar uma cópia isolada do provider de teste com quatro campos obrigatórios e o mesmo comando read-only aceito por RA1. Abrir a autenticação, conferir acesso a todos os campos, barra de status e rodapé, e clicar Cancelar sem preencher ou validar.
Esperado: os quatro campos e o rodapé ficam acessíveis dentro dos limites da janela; se a cardinalidade exigir rolagem, ela pertence somente ao formulário; nenhum validator, arquivo de sessão ou ran.
Casos de UI da autorização
Todos usam R0 e sts get-caller-identity. A janela mantém ações, resumo do escopo e status fixos no rodapé. A largura permanece estável; mudanças de modo ajustam somente a altura, preservando o centro atual. Cada decisão terminal permanece visível por um instante antes do fechamento automático.
AUTHZ-UI-01 — layout e comando enorme
- Abrir uma chamada normal, conferir os estados da barra ao marcar a confirmação e a duração e clicar Negar.
- Em raiz nova, repetir com um argumento sintético longo que não altere a natureza read-only da operação.
- Confirmar que a pílula longa mostra começo, fim e tamanho sem tooltip ilimitado; abrir a revisão paginada e percorrer ao menos duas páginas.
- Alternar Uma vez, Temporariamente,
Exacte prefixo; confirmar largura e centro estáveis, grupos fixo/variável legíveis e ações sempre acessíveis; clicar Negar.
Esperado: feedback Acesso negado. em coral; invoke, denied-interface; nenhuma autenticação, credencial, grant ou execução.
AUTHZ-UI-02 — permitir uma vez
Manter Uma vez selecionado, marcar a confirmação de revisão e clicar Permitir. Confirmar 👍 Acesso autorizado uma vez. em verde. Cancelar a autenticação que abrir em seguida.
Esperado: invoke, override-once, session-invalid; nenhum grant, credencial, cache ou ran.
AUTHZ-UI-03 — permitir temporariamente
Escolher Temporariamente, confirmar que sts get-caller-identity foi sugerido antes da primeira flag, selecionar 2 minutos, marcar a confirmação de revisão e clicar Permitir. Confirmar 👍 Acesso autorizado por 2 min. em verde. Cancelar a autenticação que abrir em seguida.
Esperado: invoke, override-timed, session-invalid; grant local presente antes do cleanup; nenhuma credencial, cache ou ran.
Casos Jasper AWS
AWS-POL-01 — accept por regra
Perfil RA1. Chamar sts get-caller-identity. Se a sessão ainda não existir dentro do caso, autenticar com candidata válida.
Esperado: nenhuma janela de autorização; allowed-by-rules; execução com exit code zero.
AWS-POL-02 — deny explícito antes de auth
Perfil RA2. Chamar sts get-caller-identity sem preparar credenciais.
Esperado: explicit-deny; nenhuma janela de autorização ou autenticação; nenhum arquivo de autenticação/cache; nenhum subprocesso AWS. Se qualquer janela aparecer, o caso falha imediatamente.
AWS-POL-03 — deny vence accept
Perfil RA3. Chamar sts get-caller-identity sem preparar credenciais.
Esperado: mesmo resultado de AWS-POL-02, com a regra negada identificada. A presença simultânea em accept não autoriza abrir janela.
AWS-POL-04 — unresolved negado
Perfil R0. Chamar sts get-caller-identity e clicar Negar.
Esperado: human-deny; denied-interface; nenhum grant, auth, cache ou subprocesso AWS.
AWS-POL-05 — permitir uma vez
Perfil R0.
- Chamar
sts get-caller-identity. - Manter Uma vez selecionado, marcar a confirmação de revisão e clicar Permitir.
- Autenticar com candidata válida quando solicitado.
- Repetir exatamente a mesma chamada.
- Confirmar que a janela de autorização reaparece e clicar Negar.
Esperado: primeira decisão human-once com override-once e um único ran; nenhum arquivo de grant; segunda decisão human-deny sem segundo ran.
AWS-POL-06 — grant temporário, escopo e expiração
Perfil R0.
- Chamar
sts get-caller-identity --query Account. - Escolher Temporariamente, selecionar Somente esta invocação exata, escolher
2minutos, marcar a confirmação de revisão e clicar Permitir. - Autenticar quando solicitado.
- Dentro da janela, chamar
sts get-caller-identity --output json. - Confirmar que a GUI reaparece: um grant
Exactnão permite argumentos acrescentados. Clicar Negar. - Esperar a expiração confirmada pelo epoch do grant, em intervalos observáveis menores que 60 segundos.
- Chamar novamente e clicar Negar quando a GUI reaparecer.
Esperado: override-timed | 2min; a repetição idêntica usa allowed-by-grant e ran; a variação e a chamada após expirar geram denied-interface e nenhum novo ran.
AWS-POL-07 — unresolved em headless
Perfil R0, TORII_NO_GUI=1, chamada sts get-caller-identity.
Esperado: human-deny/denied-interface, sem janela, auth, grant ou execução.
Casos Kubernetes
O context real padrão é escolhido localmente pelo operador e sempre exposto ao MCP apenas como lab. O target declara localmente provider, referenciando o provider instalado cujo lifecycle deve herdar. O conteúdo da credencial e os nomes reais dos contexts não entram no catálogo nem na evidência de cada instância; somente aliases, tools de provider, hashes permitidos e classificações de resultado. As rules desse provider permanecem em R0 quando o agente não precisa invocá-lo diretamente.
Exceto nos testes que verificam a própria fronteira de target, o preparo ativa lab por 30 minutos antes da primeira chamada MCP. Para K8S-TGT-08, ativa lab_a e adiciona lab_b conscientemente, registrando que ambos ficam selecionáveis pelo agente até a expiração ou limpeza.
K8S-AUTH-01 é a exceção controlada: usa um segundo context não produtivo sob o alias lab-noaccess, mas referencia o mesmo provider autenticador e usa uma identidade válida nele. O preflight do provider deve passar; a falta de acesso ao outro cluster é observada no exit code do kubectl, depois da autorização do Jasper.
K8S-POL-01 — accept no target
Compartilhado R0; target lab RK1.
get pods -n default -o name --request-timeout=10s
Esperado: allowed-by-rules, preflight-provider, sessão válida ou renovada no provider autenticador, preflight-ok, escopo kubectl/lab, exit code zero e nenhum context real na resposta/auditoria.
K8S-AUTH-01 — identidade válida sem acesso ao outro target
Pré-condição: a mesma identidade usada em K8S-POL-01 continua válida no provider autenticador. Raiz nova, provider alvo e provider autenticador, ambos com rules compartilhadas R0; target lab-noaccess RK1 e referência ao mesmo campo provider.
get pods -n default -o name --request-timeout=10s
Esperado: allowed-by-rules, preflight-provider, sessão válida no provider autenticador, preflight-ok, um único ran com exit code diferente de zero e erro classificado como Unauthorized ou Forbidden; nenhuma GUI de autorização ou grant. Exit code zero torna o caso FAIL, pois demonstraria que a identidade de referência possui acesso de leitura ao target de isolamento. Falha de rede, DNS ou obtenção de token torna o caso inconclusivo, não um PASS de isolamento.
K8S-POL-02 — deny explícito de leitura
Compartilhado R0; target lab RK2.
config view --minify
Esperado: explicit-deny, nenhuma janela e nenhum subprocesso kubectl. Se qualquer janela aparecer, o caso falha imediatamente.
K8S-POL-03 — deny vence accept
Compartilhado R0; target lab RK3; mesma chamada de K8S-POL-02.
Esperado: deny explícito vence, sem janela e sem subprocesso. A presença simultânea em accept não transforma a decisão em unresolved.
K8S-POL-04 — unresolved negado
Compartilhado e target em R0.
get namespaces --request-timeout=10s
Clicar Negar. Esperado: human-deny, nenhum grant e nenhum subprocesso kubectl.
K8S-POL-05 — permitir uma vez
Compartilhado e target em R0.
- Chamar
get namespaces --request-timeout=10s. - Manter Uma vez selecionado, marcar a confirmação de revisão e clicar Permitir.
- Repetir exatamente a chamada.
- Confirmar que a GUI reaparece e clicar Negar.
Esperado: primeira chamada override-once e ran; nenhum grant; segunda chamada denied-interface sem segundo ran.
K8S-POL-06 — grant exact, variação e expiração
Compartilhado e target em R0.
- Chamar
get pods -n agente-financeiro --request-timeout=10s. - Escolher Temporariamente, selecionar Somente esta invocação exata, escolher
2minutos, marcar a confirmação de revisão e clicar Permitir. - Repetir exatamente a chamada dentro da janela; não deve abrir GUI.
- Ainda dentro da janela, chamar
get pods -n agente-financeiro --request-timeout=10s -o name; por ser grantExact, deve abrir GUI. Clicar Negar. - Ainda dentro da janela, chamar
get pods -n agente-rm --request-timeout=10s; por ser grantExact, deve abrir GUI. Clicar Negar. - Depois da expiração, repetir a chamada original e clicar Negar.
Esperado: somente a repetição exata usa allowed-by-grant; a variação e a chamada expirada geram denied-interface.
K8S-POL-07 — grant prefix, variação e expiração
Compartilhado e target em R0, numa raiz nova para não reutilizar o grant anterior.
- Chamar
get pods -n agente-financeiro --request-timeout=10s. - Escolher Temporariamente, confirmar a sugestão
get podsantes de-n, escolher2minutos, marcar a confirmação de revisão e clicar Permitir. - Dentro da janela, chamar
get pods -n agente-rm --request-timeout=10s; não deve abrir GUI. - Ainda dentro da janela, chamar
get pods; não deve abrir GUI. - Depois da expiração, chamar
get pods -n agente-financeiro --request-timeout=10se clicar Negar.
Esperado: as chamadas cuja sequência começa por get pods usam allowed-by-grant; a chamada após expirar gera denied-interface. A evidência registra apenas o modo e a contagem de tokens do grant, nunca o conteúdo de argumentos ou credenciais.
Casos de fronteira do target
Todos usam somente o verbo read-only get pods. Como a rejeição deve ocorrer antes da política, os arquivos ficam em R0 e o log não deve ganhar invoke.
K8S-TGT-01 — target ausente
Chamar a tool kubectl sem o campo target. Esperado: erro de argumentos informando que target é obrigatório.
K8S-TGT-02 — target desconhecido
Com somente lab cadastrado, chamar com target: inexistente. Esperado: erro que anuncia apenas lab como disponível.
K8S-TGT-03 — --context
get pods --context outro
Esperado: opção locked pelo target, sem subprocesso.
K8S-TGT-04 — --kubeconfig
get pods --kubeconfig arquivo-ficticio
Esperado: opção locked, sem leitura do arquivo e sem subprocesso.
K8S-TGT-05 — --server=...
get pods --server=https://invalid.example
Esperado: opção locked, sem tentativa de rede.
K8S-TGT-06 — --token=...
get pods --token=valor-ficticio
Esperado: opção locked. O valor fictício não deve aparecer na auditoria, que deve permanecer inalterada.
K8S-TGT-07 — política do target substitui compartilhada
Compartilhado RK1. No target lab, usar:
version: "1.0"
deny:
- "get pods"
accept: []
Chamar get pods -n default --request-timeout=10s.
Esperado: deny explícito do target; a regra compartilhada não é combinada nem usada; nenhum subprocesso.
K8S-TGT-08 — grant isolado por alias
Dois aliases, lab_a e lab_b, apontam para o mesmo context não produtivo aprovado. Compartilhado e ambos os targets em R0.
- Em
lab_a, chamarget namespaces --request-timeout=10se permitir por 2 minutos. - Repetir em
lab_a; deve usar o grant sem GUI. - Dentro da mesma janela, chamar exatamente os mesmos args em
lab_b. - Confirmar que a GUI aparece e clicar Negar.
Esperado: grant existe somente sob lab_a; auditoria separa kubectl/lab_a e kubectl/lab_b.
Evidência por instância
Depois da aprovação deste catálogo, a sessão cria tests/live/runs/2026-07-15.md. Cada caso recebe uma instância antes do preparo, por exemplo LIVE-2026-07-15-001.
Cada instância registra:
- ID da instância e ID do caso;
- revisão do catálogo e commit/base do código;
- horário inicial e final;
- versões de Torii, AWS CLI e kubectl;
- raiz temporária e alias, sem context real;
- conteúdo integral dos rules aprovados e seus hashes;
- sequência de invocações e ações humanas solicitadas;
- decisão, origem, regra, exit code e presença de GUI observados;
- eventos relevantes e sanitizados de auditoria;
- presença, tamanho, hash e timestamp de grants/cache/auth quando necessários, nunca o conteúdo de credenciais;
- resultado
PASS,FAIL,BLOCKEDouNOT RUN; - bug ou divergência encontrados;
- confirmação de cleanup ou motivo aprovado para preservar a raiz.
O resumo do dia lista todas as instâncias planejadas. Um caso não executado continua explícito como NOT RUN; ele não desaparece da evidência.
Critério de aprovação do catálogo
Ao aprovar, o operador pode:
- aprovar todos os casos;
- excluir casos por ID;
- alterar a ordem;
- exigir uma pausa entre grupos;
- pedir mudança em comandos, rules ou evidência.
Qualquer mudança posterior neste arquivo invalida somente as instâncias ainda não executadas e exige nova aprovação para elas.
Limites atuais e evolução
Esta página distingue deliberadamente o que existe do que ainda precisa de prova real.
Implementado
- MCP stdio e lifecycle controlado pelo cliente;
- uma tool dinâmica por provider;
- Jasper com regras e grants;
- aprovação e autenticação GUI;
- auth
environmenteinherited; - lock de renovação por provider simples ou target;
- runner capturado, sem shell e com truncamento;
- auditoria local;
- migração AWS Gate;
- exemplos AWS e Kubernetes;
- tool Kubernetes única com targets por context;
- CLI humana de targets e isolamento de grants/cache/auth por alias;
- leases humanos por provider para aliases target-aware, com expiração, digest de binding, CAS, lock e escrita atômica;
- pacotes declarativos locais/remotos, catálogo pesquisável e upgrade que preserva estado;
- instaladores por script para Linux e Windows, com verificação do checksum publicado;
self upgradehumano, que confere o checksum antes de trocar o binário;
Reconhecido, não implementado
session_command;credential_file.
O schema aceita esses nomes para manter a direção arquitetural explícita, mas runtime retorna erro. O primeiro provider real de Azure ou GCP deve orientar a implementação correta.
Fora do escopo atual
- tool por operação;
- SDKs de nuvem substituindo os CLIs;
- parser completo de kubectl;
- assinatura criptográfica do catálogo/pacotes e remoção automatizada;
- distribuição OCI, WASM ou atualização automática sem pedido humano;
- assinatura dos binários publicados: o checksum detecta corrupção, não substitui assinatura;
- OAuth remoto;
- daemon multiusuário;
- tool MCP de reauth ou kill;
- CLI operacional;
- streaming e timeout de execução.
Regra de evolução
Uma abstração nova deve resolver duplicação observada em pelo menos dois providers ou uma necessidade operacional comprovada. Simplicidade e explicabilidade são requisitos do produto, não uma etapa temporária.