Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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, az e gcloud diretamente;
  • 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 deny explí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_profile fixam 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.

LinuxWindows
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
PATHsó com --add-to-pathautomá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:

PlataformaPacote
Windows x86_64torii-vX.Y.Z-windows-x86_64.zip
Linux x86_64torii-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, como aws ou kubectl;
  • acesso a uma interface gráfica para aprovação e coleta de credenciais, ou TORII_NO_GUI=1 para 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
  1. o humano continua usando aws, kubectl e az direto no terminal;
  2. o agente recebe uma tool por provider instalado, nunca uma tool por operação;
  3. tudo começa negado: sem accept, grant ou aprovação humana, não passa;
  4. um deny explícito vence accept, grant e aprovação humana;
  5. 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ávelEfeito
TORII_CONFIG_DIRsubstitui a raiz inteira (default ~/.config/torii)
TORII_NO_GUI=1headless: chamada não resolvida é negada, coleta é cancelada
TORII_PROVIDER_CATALOGusa 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"
FormaComo 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_argsargumento negado em qualquer posição, antes de qualquer regra
ignore_argsnormaliza o argv 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
FatoConsequência
criar alias não ativao alias aparece no schema MCP, mas a chamada exige lease
--for aceita 1 a 1.440 minsem --for, usa default_target_minutes (15)
ativação normal substituitodos os outros aliases ativos daquela tool são desativados
--add acumulao agente pode escolher qualquer alias ativo em operação permitida
clear só revoga leasesnão apaga target, rules, grants, .env, cache nem mata processos
mudou target.yamlo 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égiaReauth pelo Torii
environmentsim: janela coleta os campos e valida antes de substituir a sessão
inherited sem validatornã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_profilenã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
EventoLeitura
allowed-by-rules / allowed-by-grantpassou por accept ou por grant vivo
denied-explicitcasou um deny; nada mais foi consultado
override-once / override-timedhumano aprovou na janela, uma vez ou por tempo
target-access-*pedido, substituição, adição, revogação ou perda de lease
identity-mismatchconta 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çaReiniciar?
editar rules.yamlnão
ativar, limpar ou expirar leasenão
conceder grant temporárionão
instalar, atualizar ou remover providersim
criar ou remover targetsim
alterar PATH ou TORII_CONFIG_DIRsim

Diagnóstico rápido

SintomaPrimeira verificação
no providers installedtorii config-dir e torii provider list; init não instala providers
rules file not foundo provider não tem rules.yaml; não existe fallback permissivo
could not find the executable ... in PATHwhere <cli> no mesmo terminal e reinicie o cliente MCP
negado sem abrir janelacasou um deny, ou TORII_NO_GUI está setado
alias inativo / negado em headlesstorii target status <tool> e target activate
muitos aliases ativostarget status, depois target clear ou ativar sem --add
conta divergente em aws_profileautentique o profile e confira torii target show
execution.truncated: truesaí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

  1. Default deny. Ausência de regra ou grant não significa permissão.
  2. Deny prioritário. Um deny compatível encerra a avaliação antes de qualquer aprovação.
  3. Autorização antes de autenticação. .env, credenciais e cache não são lidos no caminho negado.
  4. Sem shell. O Torii nunca monta uma linha de comando; o programa recebe argumentos via Command::args.
  5. Credencial por processo. Material coletado pelo Torii é sobreposto somente nos filhos de validação e execução.
  6. Substituição após validação. Reauth falho preserva a sessão anterior.
  7. Concorrência serializada por escopo de autenticação. Chamadas que herdam o mesmo provider compartilham seu lock; cada alias aws_profile possui um lock próprio.
  8. Auditoria sanitizada. Logs usam uma referência curta e não armazenam clipboard, credenciais ou saída completa.
  9. Target sob controle humano. O alias resolve para configuração local; flags de troca de context, identidade e endpoint são bloqueadas.
  10. Política pertence ao operador. Install cria rules vazio; setup é o único writer e upgrade nunca toca em rules ou estado operacional.
  11. 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.
  12. 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.
  13. Consulta de política somente leitura. torii_policy pode ler as regras ativas de um provider ou target, mas não lê ambiente, credenciais, cache ou grants e não altera estado.
  14. Binding AWS humano. Um target aws_profile fixa 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.
  15. 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_DIR e CLOUDSDK_CONFIG no .env do 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:

RegraArgsResultado
s3 lss3, lscasa
s3 cps3, cp, a, bcasa
s3 lss3api, list-bucketsnão casa
ec2 describeec2, describe-instancesnã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 primeiros N argumentos 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:

PacoteTool MCPAutenticaçãoTarget-aware
awsawsenvironment, coletada pelo Toriinão
aws-profileaws_profileinherited por profile humano, com conferência de contasim
azazinherited do az loginnão
kubectlkubectldelegada ao provider de identidade do targetsim
snowsnowinheritednã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 é:

  1. carregar a sessão existente após a autorização;
  2. usar cache curto se houver validação recente;
  3. executar o comando de validação;
  4. se inválida, abrir a janela gerada pelos campos;
  5. 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;
  6. persistir atomicamente e atualizar o cache;
  7. 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 s3 e s3api;
  • 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 (ou az login --tenant <tenant>);
  • torii reauth az nã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óprio az na 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 show antes 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:

CategoriaExemplos negados
emissão de credencial ou tokenaccount 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 segredokeyvault secret show, keyvault secret download, keyvault key download, keyvault certificate download
execução remotavm run-command invoke, ssh vm
canais que escapam da curadoriarest, 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 como updated_at não casam, porque _ conta como caractere de palavra e não há fronteira \b ali);
  • 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:

  1. deixe no config.toml apenas a connection que o agente pode usar, com um role read-only;
  2. acrescente ao provider.yaml as flags de conexão ao forbidden_args, por exemplo --connection, -c, --account, --user, --role, --warehouse, --database, --private-key-file e --temporary-connection, para que uma troca de identidade seja negada antes de qualquer regra;
  3. 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:

AdapterMCPHook
codex, claude, gemini, cursor, antigravitysimsim
opencode, copilot, copilot-clisimnão existe no cliente
pisomente 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 em target/debug. Prefira uma release instalada antes de configurar o agente.

Arquivos alterados

AdapterMCPChaveHook
Codex$CODEX_HOME/config.tomlmcp_servers$CODEX_HOME/hooks.json
Claude Code~/.claude.jsonmcpServers~/.claude/settings.json
Gemini CLI$GEMINI_CLI_HOME/.gemini/settings.jsonmcpServerso mesmo settings.json
Cursor~/.cursor/mcp.jsonmcpServers~/.cursor/hooks.json
Antigravity~/.gemini/config/mcp_config.jsonmcpServers~/.gemini/config/hooks.json
opencode$XDG_CONFIG_HOME/opencode/opencode.jsonmcp
Copilot no VS Codemcp.json do perfil do usuárioservers
Copilot CLI$COPILOT_HOME/mcp-config.jsonmcpServers
pi~/.pi/agent/mcp.jsonmcpServers

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:

AdapterEvento protegidoTool de shell
CodexPreToolUseBash
Claude CodePreToolUseBash
Gemini CLIBeforeToolrun_shell_command
CursorbeforeShellExecutionshell do agente
AntigravityPreToolUse com matcherrun_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:

  1. instruções MCP orientam o agente;
  2. o hook bloqueia chamadas diretas reconhecidas;
  3. o sandbox do agente limita caminhos alternativos;
  4. 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ão 2 com 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 probe auth.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

CampoObrigatórioDescrição
versionsimdeve ser "1"
namesimidentidade lógica única
toolsimnome MCP único; torii_policy é reservado pelo Torii
descriptionsimdescrição exposta ao cliente
commandsimexecutável real
args_prefixnãoargumentos confiáveis antes dos argumentos MCP
targetingnãotorna a tool target-aware
policynãoparâmetros do Jasper
authnãoestratégia de sessão; padrão inherited
environmentnãoarquivo 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:

CampoObrigatórioDescrição
providersimtool de um provider instalado e não target-aware que roda o lifecycle de autenticação
scopenãobalde de credencial em identities/<scope>; default = nome do target
profilenãoprofile a injetar (via auth.profile_env do provider de identidade)
expectnãoidentidade 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 campo field. Um target com identity.expect compara 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 o identity.profile do target — por exemplo AWS_PROFILE, para que o plugin de credencial exec do kubectl herde o profile.
  • auth.removed_env lista 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.

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, é:

  1. baixar o index.yaml canônico;
  2. localizar a entrada cujo name é aws;
  3. resolver e baixar a URL HTTPS declarada em source;
  4. comparar o SHA-256 do conteúdo com o valor do índice;
  5. extrair em diretório temporário e validar manifest, provider, regras vazias e setups;
  6. 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
ComandoEfeito
toriiinicia o servidor MCP stdio
torii --version ou torii -Vimprime a versão do binário
torii initcria raiz e settings, sem instalar providers
torii config-dirimprime o diretório de configuração
torii self upgrade [--check]troca o próprio binário pela última release
torii provider listlista 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> --forcerevoga o lease e remove o target e seu estado isolado
torii agent listlista 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 $EDITORnotepad 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-rules e allowed-by-grant;
  • denied-explicit e denied-interface;
  • override-once e override-timed;
  • invalid-accept;
  • session-ok, session-unchecked, session-invalid, session-refreshed e session-candidate-invalid;
  • preflight-provider, preflight-ok e preflight-failed;
  • identity-ok, identity-mismatch e identity-check-failed;
  • target-access-requested, target-access-denied, target-access-replaced, target-access-added, target-access-stale, target-access-lost, target-access-revoked e target-access-cleared;
  • reauth-forced;
  • ran com 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_DIR na configuração do cliente;
  • use torii provider list fora 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.rs e reference/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.md e reference/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;
  • s3 não casando com s3api;
  • grant exact recusando argumento acrescentado, removido ou alterado;
  • grant prefix permitindo 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_profile mantendo 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 clear preservando grants, .env, cache, credenciais, target.yaml e 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

  1. Toda operação enviada a AWS ou Kubernetes deve ser estritamente de leitura.
  2. Cada caso começa em uma raiz nova TORII_CONFIG_DIR com prefixo torii-live-<caso>- sob o diretório temporário do sistema.
  3. 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.
  4. O rules.yaml começa vazio e recebe somente as regras indispensáveis para aquele caso.
  5. 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.
  6. 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.
  7. O agente confere resposta MCP, arquivos locais permitidos e eventos sanitizados de torii.log.
  8. Credenciais, conteúdo de auth/credentials.env, clipboard e stdout/stderr completos não entram na evidência.
  9. 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.
  10. 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.
  11. 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.
  12. 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-01 usa um segundo target não produtivo sob o alias lab-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 como explicit-deny; não abre janela de autorização nem de autenticação e não inicia o provider;
  • match em accept: segue como allowed-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 deny ou accept, mas com grant ativo: segue como allowed-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ÁreaObjetivoPerfilInteração humana
MCP-01MCPdiscovery e schema das toolsR0 em ambosnenhuma
AWS-AUTH-01autenticaçãocampos obrigatórios vaziosRA1Validar e usar; depois fechar/cancelar
AWS-AUTH-02autenticaçãocancelamento sem sessãoRA1Cancelar
AWS-AUTH-03autenticaçãocandidata inválida não persisteRA1credencial inválida; Validar e usar; Cancelar
AWS-AUTH-04autenticaçãocandidata válida é validada e usadaRA1credencial temporária válida; Validar e usar
AWS-AUTH-05autenticaçãoreauth inválido preserva sessão válidaRA1sessão válida; reauth inválido; Cancelar
AUTH-UI-01autenticaçãolayout mínimo com uma variávelRA1 em provider de testeconferir layout; Cancelar
AUTH-UI-02autenticaçãolayout com quatro variáveisRA1 em provider de testeconferir layout; Cancelar
AUTHZ-UI-01autorizaçãolayout normal e comando enormeR0conferir estados e rolagem; Negar
AUTHZ-UI-02autorizaçãofeedback de permitir uma vezR0Permitir uma vez; Cancelar auth
AUTHZ-UI-03autorizaçãosugestão estrutural, expansão e feedback temporárioR0Temporariamente, prefixo sugerido, 2 min; Cancelar auth
AWS-POL-01Jasperaccept executa sem prompt de acessoRA1autenticar se necessário
AWS-POL-02Jasperdeny explícito encerra antes de authRA2nenhuma
AWS-POL-03Jasperdeny vence acceptRA3nenhuma
AWS-POL-04Jasperunresolved negado pelo humanoR0Negar
AWS-POL-05Jasperallow once não persisteR0Permitir uma vez; na repetição, Negar
AWS-POL-06Jaspergrant de 2 min, escopo e expiraçãoR0Temporariamente, Exact, 2 min; ao expirar, Negar
AWS-POL-07Jasperheadless mantém default denyR0nenhuma
K8S-POL-01Jasper/targetaccept no target selecionadoR0 compartilhado + RK1 no targetnenhuma
K8S-AUTH-01autenticação herdadaidentidade válida sem acesso ao target de isolamentoR0 compartilhado + RK1 no targetnenhuma
K8S-POL-02Jasper/targetdeny explícito de leituraR0 compartilhado + RK2 no targetnenhuma
K8S-POL-03Jasper/targetdeny vence acceptR0 compartilhado + RK3 no targetnenhuma
K8S-POL-04Jasper/targetunresolved negado pelo humanoR0 compartilhado e no targetNegar
K8S-POL-05Jasper/targetallow once não persisteR0 compartilhado e no targetPermitir uma vez; na repetição, Negar
K8S-POL-06Jasper/targetgrant exact, variação e expiraçãoR0 compartilhado e no targetTemporariamente, Exact, 2 min; negar variação e expiração
K8S-POL-07Jasper/targetgrant prefix, variação e expiraçãoR0 compartilhado e no targetTemporariamente, prefixo get pods, 2 min; negar após expiração
K8S-TGT-01envelopetarget obrigatórioR0nenhuma
K8S-TGT-02envelopetarget desconhecidoR0nenhuma
K8S-TGT-03envelopebloqueio de --contextR0nenhuma
K8S-TGT-04envelopebloqueio de --kubeconfigR0nenhuma
K8S-TGT-05envelopebloqueio de --serverR0nenhuma
K8S-TGT-06envelopebloqueio de --tokenR0nenhuma
K8S-TGT-07políticaregra do target substitui compartilhadaRK1 compartilhado + deny mínimo no targetnenhuma
K8S-TGT-08isolamentogrant de um alias não atravessa outroR0 em dois targetsTemporariamente, 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 aws e kubectl;
  • aws exige apenas args;
  • kubectl exige target e args;
  • o enum de target anuncia somente lab;
  • lab continua 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.log permanece 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

  1. Chamar sts get-caller-identity.
  2. Confirmar que a altura da janela acompanha o formulário, sem espaço vertical excessivo e com campos e botões acessíveis.
  3. Clicar Validar e usar sem preencher campos.
  4. 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

  1. Chamar sts get-caller-identity.
  2. Clicar Cancelar.

Esperado: erro estruturado de autenticação cancelada; nenhum arquivo de sessão; nenhum ran.

AWS-AUTH-03 — candidata inválida

  1. Chamar sts get-caller-identity.
  2. Preencher valores temporários deliberadamente inválidos, sem registrá-los na evidência.
  3. Clicar Validar e usar.
  4. Confirmar que a mesma janela permanece aberta, o formulário fica bloqueado e um indicador de progresso aparece durante a validação.
  5. 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

  1. Chamar sts get-caller-identity.
  2. 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

  1. Criar uma sessão válida dentro do próprio caso e registrar hash/timestamp de credentials.env sem abri-lo.
  2. Executar torii reauth aws na mesma raiz.
  3. Informar uma candidata inválida, clicar Validar e usar, observar a recusa e clicar Cancelar.
  4. Conferir que hash/timestamp do arquivo anterior não mudaram.
  5. Chamar sts get-caller-identity por 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

  1. Abrir uma chamada normal, conferir os estados da barra ao marcar a confirmação e a duração e clicar Negar.
  2. Em raiz nova, repetir com um argumento sintético longo que não altere a natureza read-only da operação.
  3. 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.
  4. Alternar Uma vez, Temporariamente, Exact e 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.

  1. Chamar sts get-caller-identity.
  2. Manter Uma vez selecionado, marcar a confirmação de revisão e clicar Permitir.
  3. Autenticar com candidata válida quando solicitado.
  4. Repetir exatamente a mesma chamada.
  5. 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.

  1. Chamar sts get-caller-identity --query Account.
  2. Escolher Temporariamente, selecionar Somente esta invocação exata, escolher 2 minutos, marcar a confirmação de revisão e clicar Permitir.
  3. Autenticar quando solicitado.
  4. Dentro da janela, chamar sts get-caller-identity --output json.
  5. Confirmar que a GUI reaparece: um grant Exact não permite argumentos acrescentados. Clicar Negar.
  6. Esperar a expiração confirmada pelo epoch do grant, em intervalos observáveis menores que 60 segundos.
  7. 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.

  1. Chamar get namespaces --request-timeout=10s.
  2. Manter Uma vez selecionado, marcar a confirmação de revisão e clicar Permitir.
  3. Repetir exatamente a chamada.
  4. 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.

  1. Chamar get pods -n agente-financeiro --request-timeout=10s.
  2. Escolher Temporariamente, selecionar Somente esta invocação exata, escolher 2 minutos, marcar a confirmação de revisão e clicar Permitir.
  3. Repetir exatamente a chamada dentro da janela; não deve abrir GUI.
  4. Ainda dentro da janela, chamar get pods -n agente-financeiro --request-timeout=10s -o name; por ser grant Exact, deve abrir GUI. Clicar Negar.
  5. Ainda dentro da janela, chamar get pods -n agente-rm --request-timeout=10s; por ser grant Exact, deve abrir GUI. Clicar Negar.
  6. 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.

  1. Chamar get pods -n agente-financeiro --request-timeout=10s.
  2. Escolher Temporariamente, confirmar a sugestão get pods antes de -n, escolher 2 minutos, marcar a confirmação de revisão e clicar Permitir.
  3. Dentro da janela, chamar get pods -n agente-rm --request-timeout=10s; não deve abrir GUI.
  4. Ainda dentro da janela, chamar get pods; não deve abrir GUI.
  5. Depois da expiração, chamar get pods -n agente-financeiro --request-timeout=10s e 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.

  1. Em lab_a, chamar get namespaces --request-timeout=10s e permitir por 2 minutos.
  2. Repetir em lab_a; deve usar o grant sem GUI.
  3. Dentro da mesma janela, chamar exatamente os mesmos args em lab_b.
  4. 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, BLOCKED ou NOT 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.

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 environment e inherited;
  • 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 upgrade humano, 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.