name: xpz-llm-delegate description: Permite ao agente principal delegar tarefas menores, pedir segunda opinião ou conduzir revisão por pares/peer review de plano/design por painel multi-modelo via opencode, Codex, Claude Code (Opus 4.8), GitHub Copilot CLI ou Gemini CLI; ao receber "revisão por pares", carregar esta skill, perguntar revisores preferidos se não houver preferred-reviewers.json, não presumir assinatura externa e nunca rotular parecer solo como revisão por pares; acionamento sempre humano
xpz-llm-delegate
Permite ao agente principal (forte) delegar tarefas menores ou pedir segunda opinião a um LLM secundário, sem ceder a ele o juízo das decisões complexas. A delegação é uma ferramenta dirigida pelo humano: nunca é acionada automaticamente pelo agente — só a pedido do usuário ou com a concordância explícita dele a uma sugestão.
Há cinco motores de delegação (backends): o opencode (backend #1, agêntico), o
Codex (backend #2, codex exec, usando o default da própria ferramenta quando -Model é omitido), o Claude Code
(backend #3, claude -p com Opus 4.8 por padrão), o GitHub Copilot CLI
(backend #4, copilot -p) e o Gemini CLI (backend #5, gemini -p). A skill é backend-agnóstica:
o núcleo (classificação de localidade, política de confidencialidade por KB, validação de
saída) é o mesmo para todos; cada backend só contribui seu adapter de invocação e seu
resolvedor de localidade. O backend é distinguido pelo script que se chama
(Invoke-Codex, Invoke-OpenCode, Invoke-ClaudeCode, Invoke-Copilot ou Invoke-Gemini) e pelo parâmetro -Backend
do gate — nunca pela chave de modelo na política (ver ## ANATOMIA).
Esta skill é transversal — opera tanto na raiz de desenvolvimento das skills XPZ
quanto, com regras mais estreitas, em sessão dentro de uma pasta paralela de KB.
Ela não manipula XPZ/XML; o prefixo xpz- é marcador de família, como em
xpz-skills-setup.
Este mecanismo sustenta a revisão por pares — submeter um manuscrito a um painel de
revisores de modelos distintos, que pensam por si e leem as fontes. A metodologia genérica
e a régua de convergência são normativas em 15-revisao-por-pares.md;
o caso pré-push dela é o painel de 14-revisao-pre-push-reforcada.md.
Os documentos guardam a metodologia/política; esta skill guarda o mecanismo de delegação.
CONTRATO DE ENTRADA — REVISÃO POR PARES
Quando o usuário pedir revisão por pares, peer review, painel multi-modelo ou
validar plano multi-modelo, esta skill deve ser carregada e aplicada antes de responder.
Não trate esses termos como sinônimo de parecer crítico solo.
Regra prática para o agente consumidor:
- Ler este
SKILL.mde, quando disponível no repositório de origem/instalação, a metodologia15-revisao-por-pares.md. Mesmo sem o15, os passos 2-7 abaixo são o contrato mínimo para não rotular parecer solo como revisão por pares. - Resolver a lista de revisores preferidos rodando
Resolve-LlmDelegatePreferredReviewers.ps1. Opreferred-reviewers.jsoné machine-level: vive em%LOCALAPPDATA%\xpz-llm-delegate\preferred-reviewers.json, fora do repositório. Não procurá-lo no repo (Glob/find/ls/Grep) — a busca no repositório sempre dá vazio, e concluirhasPreferences=falsea partir disso é anti-padrão; a única fonte de verdade é ohasPreferencesdevolvido pelo resolvedor. O mesmo vale para ocapabilities.json(mesmo diretório machine-level). - Se não houver lista, perguntar ao usuário quais ferramentas/modelos ele tem disponíveis ou
prefere, usando nomes reconhecíveis:
Claude Code,opencode/Ollama Cloud,Codex,Copilot,Gemini, ou subagente nativo da ferramenta atual. A pergunta deve calibrar preferência humana, não enumerar tudo que está instalado como menu prescritivo. Backend detectado sem preferência registrada deve aparecer como "detectado; confirme se quer usar", nunca como recomendação implícita. Não sugerir "caminho mais simples" com serviço externo sem preferência confirmada. Se a conversa já registrar ferramentas preferidas do usuário, use esse contexto antes de citar alternativas genéricas. Não presumir assinatura de Gemini, Copilot, Codex cloud ou qualquer serviço externo sem confirmação ou preferência registrada. Depois que o usuário escolher revisores para a rodada sem lista preferida, oferecer salvar essa seleção já feita como curadoria machine-level empreferred-reviewers.json; não confundir essa oferta com autorização por KB. - Incluir subagente nativo quando fizer sentido: ele pode participar, mas conta como a família do orquestrador e não substitui uma família externa para cumprir o piso de diversidade.
- Rodar o gate de autorização por destino e o piso de diversidade antes de consultar revisores.
- Antes do recibo final, rodar
Resolve-LlmDelegatePeerReviewCloseout.ps1. Se a rodada começou sempreferred-reviewers.jsone o usuário escolheu revisores manualmente, o closeout deve bloquear enquanto a oferta de salvar essa seleção não tiver sido feita. Sepreferred-reviewers.jsonjá existia, o closeout deve receber o estado final de cada revisor preferido da rodada; preferido não pode virar pool opcional silencioso. Ao autorar a versão consolidada (vN+1), passar-VNextState pendingResubmission— o closeout bloqueia atéresubmittedou declínio auditado (resubmissionDeclinedByHuman+-ResubmissionDeclinedBy-ResubmissionDeclineReason+-RoundId). Dois subcasos do mesmoresubmissionDeclinedByHumandistinguem-se pelo-ResubmissionDeclineReason: (a) congelamento do design — o humano decide parar de iterar no papel e transferir a prova para implementação/self-test (motivo ex.:"prova transferida para implementação/self-test"; ver15-revisao-por-pares.md, seção## Quando o design estabiliza: congelar o papel e migrar para o código); (b) abandono do ciclo sem substituto de prova. Em ambos o estado não éresubmitted— a vN+1 não foi revisada pelo painel.
- Só usar o rótulo
revisão por paresse houver painel válido (≥2 famílias efetivamente consultadas) e recibo mínimo: arquivos lidos, manuscrito/prompt, revisores, famílias, resultado do piso, vereditos e o estado da vN+1 (vNextState). Sem isso, rotular comoparecer soloousegunda opinião (N).
Resposta em menos de 30 segundos desde o pedido é evidência de que revisão por pares real não aconteceu, salvo quando o agente estiver apenas reportando painel anterior identificável por recibo/livro-razão.
GUIDELINE
- Acionamento só humano. Nunca invocar um subagente por conta própria. O agente pode sugerir delegar; só executa após pedido ou concordância explícita do usuário.
- O agente forte mantém o juízo. Nunca delegar decisão estrutural GeneXus
(classificação de risco de objeto, segurança de import, juízo de família/tipo,
veredito de gate). Isso fica sempre com o agente principal — ver
## O QUE NÃO DELEGAR. - Validar a saída do subagente. Toda saída de tarefa delegada é insumo, não verdade.
O agente forte revisa antes de usar. Modelos fracos não são confiáveis como piloto
solo de conteúdo GeneXus (ver
README.md, regra de modelos de linguagem); como voz num painel de revisão por pares são admissíveis (nunca decisivos sozinhos). - Confidencialidade por gate determinístico. Antes de enviar qualquer payload a um
modelo, classificar o payload (
kb-sensitiveoupublic) e passar porResolve-LlmDelegateAuthorization.ps1. Conteúdo de KB só vai a modelo externo com autorização; conteúdo público é livre — ver## CONFIDENCIALIDADE. - Anunciar o destino. Mesmo com autorização durável, declarar ao usuário para qual modelo (e se local ou externo) o conteúdo está indo a cada uso.
- Recusa não é o padrão; autorização é. Para payload sensível a modelo externo sem
política durável, o gate devolve
ask— o agente pede autorização explícita e oferece persistir a escolha no arquivo de política da KB (liberação durável). Em revisão por pares, osaskque faltam para o piso de diversidade (≥2 famílias) são apresentados juntos para uma decisão humana única (anunciando destinos + sensibilidade), nunca descartados em silêncio — o gate continua decidindo por destino. VerResolve-LlmDelegatePanelDiversity.ps1e15-revisao-por-pares.md. - Não confiar no relógio nem em fatos reportados pelo subagente. Timestamps, contagens e afirmações vindas do modelo secundário podem ser alucinados; validar.
CONTEXTOS DE USO (uma coisa não atrapalha a outra)
| Contexto | Classe de dado típica | Regra |
|---|---|---|
| Raiz de desenvolvimento das skills XPZ | público (diff do repo, molde sanitizado, README) | externo liberado; é o caso nobre da diversidade de modelo (segunda opinião na revisão pré-push) — externo é até desejável, pois diversidade quer um modelo diferente do principal |
| Sessão dentro de pasta paralela de KB | sensível (conteúdo real de KB, ObjetosDaKbEmXml, XML) |
externo exige autorização (gate); preferir modelo local; o subagente agêntico não tem proteção nativa de leitura na pasta paralela — ver ## CONFIDENCIALIDADE |
A revisão pré-push (13-revisao-pre-push.md) não se aplica a pastas paralelas. O caso
de diversidade de modelo vive na raiz de desenvolvimento, não na pasta paralela. (A validação
pré-push do estado de uma pasta paralela de KB — gates mecânicos antes do push dessa KB — é
a skill xpz-kb-parallel-pre-push: rotina distinta da do
13 e que não usa este mecanismo de delegação.)
ANATOMIA (cada parte faz o quê, e qual eixo governa)
A skill separa três eixos independentes. Confundi-los gera erro (ex.: namespear a política pelo backend abre brecha de confidencialidade). Os eixos:
| Eixo | Pergunta | Onde mora |
|---|---|---|
| Tarefa | é delegável (mecânica/2ª opinião) ou é juízo GeneXus? | ## O QUE NÃO DELEGAR |
| Adapter (como o dado é enviado) | qual motor leva o prompt? | o script que se chama (Invoke-Codex, Invoke-OpenCode, Invoke-ClaudeCode, Invoke-Copilot, Invoke-Gemini) |
| Destino (para onde o dado vai) | o tráfego sai da máquina? para qual provider? | resolvedor de localidade + política |
Invariante de destino (a regra que evita o erro): a chave de modelo no gate e na
política é o provider/modelo de DESTINO — para onde o tráfego vai. Adapters diferentes
que enviam para o mesmo provider normalizam para a mesma chave; o backend/adapter
nunca entra na chave. Por isso o Codex com gpt-5.5 explícito ou derivado da config (que vai para a OpenAI) casa a chave
openai/gpt-5.5 e é governado pelas mesmas regras openai/* que o opencode — não por uma
chave codex/*. Namespear por adapter faria uma regra openai/*: deny-external deixar o
Codex passar: brecha silenciosa no eixo que o gate existe para proteger. Pelo mesmo motivo,
Claude Code com Opus 4.8 casa anthropic/claude-opus-4-8, nunca claude-code/*.
GitHub Copilot CLI casa github-copilot/<modelo> (ex.: github-copilot/gpt-5-mini),
nunca openai/*, porque o destino operacional é o serviço Copilot. Gemini CLI casa
google/<modelo> (ex.: google/gemini-3-flash-preview).
Mapa de responsabilidade por componente (em scripts/, na raiz):
| Componente | Governa | Não faz |
|---|---|---|
Invoke-* / Start-*Job (adapter) |
como o prompt é enviado (mecânica do motor) | não decide destino nem confidencialidade |
Resolve-OpenCodeModelLocality / Resolve-CodexModelLocality / Resolve-ClaudeCodeModelLocality / Resolve-CopilotModelLocality / Resolve-GeminiModelLocality |
traduz a invocação → provider/modelo de destino (canonicalModel) + local/external |
não lê o payload |
Resolve-LlmDelegateAuthorization (gate) |
veredito allow/ask/deny por destino + sensibilidade + política | não envia nada; seleciona o resolvedor por -Backend |
llm-delegation-policy.json (política por-KB; nome legado opencode-delegation-policy.json ainda aceito) |
autorização durável por chave de destino | não conhece o adapter |
CONFIDENCIALIDADE
A classificação local vs externo é determinística, lida da config do backend pelo
baseURL/base_url do provider de destino (loopback ⇒ local; caso contrário ⇒ externo).
No opencode vem da config JSON; provedores cloud conhecidos (ollama-cloud/*,
opencode-go/*) são classificados como externos mesmo quando a config local não está legível.
No Codex, a classificação vem da config.toml (model, model_providers/profiles) ou
das flags --oss/--local-provider; quando -Model é omitido, vale o default do próprio Codex/config.
No Claude Code, modelos Claude explícitos são tratados como destino Anthropic externo;
opus é normalizado conservadoramente para anthropic/claude-opus-4-8, e aliases não
mapeados ficam unknown.
No Copilot CLI, o destino é sempre externo e normalizado para github-copilot/<modelo>.
No Gemini CLI, o destino é sempre externo e normalizado para google/<modelo>.
Já a pergunta "este payload é sensível?" não é determinística — ancora no
contexto/origem, não em varrer o texto. Não há selo técnico: o que segura é gatilho
humano + gate + contrato.
Dois eixos independentes:
- Tipo de tarefa (governa confiabilidade): mecânica/segunda-opinião pode ir a modelo secundário; juízo GeneXus, não.
- Sensibilidade do payload (governa confidencialidade): conteúdo de KB → só modelo local, salvo autorização; texto público → externo livre.
Scripts do gate (em scripts/, na raiz do repositório):
Resolve-OpenCodeModelLocality.ps1 -Model <provider/modelo>→ JSON{ locality: local|external|unknown, baseUrl, reason }. Backend opencode;ollama-cloud/*eopencode-go/*são externos conhecidos mesmo sem config legível.Resolve-CodexModelLocality.ps1 [-Model <m>] [-Oss] [-LocalProvider <ollama|lmstudio>] [-Profile <id>]→ JSON{ locality, baseUrl, canonicalModel, reason }. Backend codex; quando-Modelé omitido, tenta derivar o modelo doconfig.toml;canonicalModelé a chave de destino (ex.:openai/gpt-5.5).Resolve-ClaudeCodeModelLocality.ps1 [-Model <m>]→ JSON{ locality, canonicalModel, reason }. Backend Claude Code;opuseclaude-opus-4-8casamanthropic/claude-opus-4-8.Resolve-CopilotModelLocality.ps1 [-Model <m>]→ JSON{ locality, canonicalModel, reason }. Backend Copilot;canonicalModelcasagithub-copilot/<modelo>.Resolve-GeminiModelLocality.ps1 [-Model <m>]→ JSON{ locality, canonicalModel, reason }. Backend Gemini;canonicalModelcasagoogle/<modelo>.Resolve-LlmDelegateAuthorization.ps1 [-Model <m>] -PayloadSensitivity <kb-sensitive|public> [-Backend <opencode|codex|claude-code|copilot|gemini>] [-Oss] [-LocalProvider <p>] [-Profile <id>] [-ConfigPath <opencode.json|config.toml>] [-PolicyPath <json>] [-ParallelKbRoot <dir>]→ JSON{ verdict: allow|ask|deny, targetModelKey, policyNameStatus, ... }. Núcleo backend-agnóstico; seleciona o resolvedor por-Backende casa a política pela chave de destino.-ConfigPathé repassado ao resolvedor de localidade (config do backend:opencode.jsonno opencode,config.tomlno codex). Com-ParallelKbRoot(e sem-PolicyPath), descobre a política pelo nome canônico com fallback ao legado e reportapolicyNameStatus;-PolicyPathexplícito prevalece.
Lógica do gate:
payload = public -> allow (qualquer modelo)
payload = kb-sensitive:
localidade local -> allow (dado não sai da máquina)
localidade external/unknown -> política por-KB:
allow-external -> allow (anunciar destino)
deny-external -> deny
ask / não definido -> ask (autorização explícita do usuário)
ARQUIVO DE POLÍTICA POR KB
Nome canônico: llm-delegation-policy.json na raiz da pasta paralela da KB (criado/ofertado
pelo xpz-kb-parallel-setup, ou ao persistir uma autorização). O nome legado
opencode-delegation-policy.json — herdado de quando só existia o backend opencode —
permanece aceito indefinidamente para retrocompatibilidade; o arquivo governa todos os
backends pela chave de destino, então o nome de um backend específico é apenas histórico.
scripts/Resolve-LlmDelegationPolicyPath.ps1 -ParallelKbRoot <raiz> resolve o caminho efetivo
(canônico com fallback ao legado) e devolve status new|legacy|both|none; o gate aceita
-ParallelKbRoot e usa esse resolvedor quando -PolicyPath é omitido. Granularidade fina por
provider/modelo, com curinga de provider e default. Ausente ⇒ comportamento ask.
{
"schemaVersion": 1,
"defaultExternal": "ask",
"models": {
"openai/gpt-5.4": "allow-external",
"ollama-cloud/*": "deny-external"
}
}
Resolução do modelo na política: chave exata → curinga provider/* → curinga * →
defaultExternal → ask (quando não há arquivo). Valores válidos por entrada:
allow-external, deny-external, ask.
A chave é sempre o provider de destino (ver ## ANATOMIA), não o backend. O Codex com
gpt-5.5 casa openai/gpt-5.5 / openai/* — as mesmas entradas que governam o opencode
quando manda para a OpenAI. Não existe (nem deve existir) prefixo codex/ na política.
O Claude Code com Opus 4.8 casa anthropic/claude-opus-4-8 / anthropic/*; não existe
prefixo claude-code/ na política.
O Copilot CLI casa github-copilot/gpt-5-mini / github-copilot/*; não existe prefixo
copilot/ na política. O Gemini CLI casa google/gemini-3-flash-preview / google/*;
não existe prefixo gemini/ na política.
O QUE NÃO DELEGAR
Fica sempre com o agente forte (nunca no subagente):
- Classificação de risco/família/tipo de objeto GeneXus
- Decisão de segurança de import/build e veredito de qualquer gate
- Interpretação de Source/Rules/Events para decisão de empacotamento
- Qualquer decisão que vire ação de escrita na KB ou no repositório
TAREFAS DELEGÁVEIS (sugestões iniciais, não exaustivas)
- Resumir um log longo / saída verbosa
- Reformatar ou normalizar texto
- Rascunhar mensagem de commit a partir de um diff
- Tradução das seções
Español/EnglishdoREADME.md(trabalho recorrente) - Segunda opinião de modelo distinto na revisão semântica pré-push (diversidade de
modelo do
13) — payload público (diff/.mddo repo) - Transformações mecânicas de texto que o agente forte valida depois
TRIGGERS
Use esta skill para:
- Delegar uma tarefa menor a um LLM secundário, a pedido do usuário ou com a concordância dele a uma sugestão
- Pedir segunda opinião de um modelo distinto (ex.: diversidade de modelo na revisão pré-push)
- Conduzir uma revisão por pares de um plano/design — montar um painel multi-modelo e ofertar a composição conforme os modelos/backends disponíveis na máquina (gatilhos: "revisão por pares", "peer review", "painel de modelos", "validar plano multi-modelo"); ver
15-revisao-por-pares.md - Calibrar e usar a lista de revisores preferidos (
preferred-reviewers.json) que alimenta a oferta de painel sem re-sondar; no 1º uso de revisão por pares sem lista, perguntar ao usuário quais ferramentas/modelos ele tem disponíveis ou prefere, em linguagem de ferramenta (Claude Code,opencode/Ollama Cloud,Codex,Copilot,Gemini, subagente nativo), antes de oferecer painel — verSet-/Resolve-LlmDelegatePreferredReviewers.ps1 - Disparar uma tarefa longa sem bloquear (job assíncrono com janela de acompanhamento)
- Delegar a um sub-agente Codex (
codex exec) — síncrono ou assíncrono - Delegar a um sub-agente Claude Code (
claude -p, Opus 4.8) — síncrono ou assíncrono - Delegar consulta curta ao GitHub Copilot CLI (
copilot -p) — síncrono - Delegar consulta curta ao Gemini CLI (
gemini -p) — síncrono - Classificar se um modelo do opencode, Codex, Claude Code, Copilot ou Gemini é local ou externo
- Decidir, via gate, se um payload pode ser enviado a um modelo (allow/ask/deny), em qualquer backend
Do NOT use esta skill para:
- Delegar juízo estrutural GeneXus (ver
## O QUE NÃO DELEGAR) - Enviar conteúdo de pasta paralela de KB a modelo externo sem passar pelo gate
- Acionar um subagente automaticamente sem pedido/concordância do usuário
- Registrar a própria skill nas ferramentas (use
xpz-skills-setup) - Preparar a pasta paralela de uma KB (use
xpz-kb-parallel-setup)
SCRIPTS (em scripts/, na raiz do repositório)
Backend opencode:
Invoke-OpenCode.ps1 [-Message <prompt> | -MessagePath <arquivo>] [-Model <p/m>] [-Agent <n>] [-OpenCodeExe <path>] [-Raw] [-AllText] [-TimeoutSec <s>] [-MaxAttempts <1-3>]— síncrono (prompt → texto). Bloqueia até a resposta.-AllTextdevolve toda a narração (preâmbulos + resposta) em vez de só a resposta final. Entrega o prompt por stdin (arquivo viaStart-Process -RedirectStandardInput), fora do argv;-MessagePathlê o prompt de um arquivo (exclusivo com-Message);-OpenCodeExeforça oopencode.exe.-MaxAttempts(default 1) liga o retry-once opt-in (ver «Detecção de truncamento (Achado D)» → «Retry-once»).Start-OpenCodeJob.ps1 [-Message <prompt> | -MessagePath <arquivo>] [-Model <p/m>] [-Agent <n>] [-OpenCodeExe <path>] [-NoWatcher] [-TempDir <path>] [-KeepDays <n>]— assíncrono; retorna{jobId, pid, stream, result, watcher}; abre janela de acompanhamento por padrão. Entrega o prompt por stdin (<GUID>.stdin.txt), sem runner (espelha Start-CodexJob).Watch-OpenCodeJob.ps1 -JobId <guid> -ProcessId <pid> [-TempDir <path>] [-IntervalSeconds <1-30>] [-SilenceThresholdSeconds <30-3600>]— monitor incremental; grava<GUID>.result.jsonao fim (camposstatus,finalText,error,tokens,totalCost,finishReason). Ostatuspode sercompleted,truncado,sem-conclusao,sem-textoouerror(Achado D: classificação porreasondo últimostep_finish; ver «Detecção de truncamento»).
No backend opencode, -Model deve usar o identificador aceito pelo CLI no formato
provider/modelo. Para Ollama Cloud, use ollama-cloud/deepseek-v4-pro; o nome curto
deepseek-v4-pro não identifica o provider e tende a falhar antes da chamada.
Backend codex (codex exec, default da própria ferramenta/config quando -Model é omitido, sandbox read-only fixo):
Invoke-Codex.ps1 [-Message <prompt> | -MessagePath <arquivo>] [-Model <m>] [-Oss] [-LocalProvider <ollama|lmstudio>] [-Profile <id>] [-Cd <dir>] [-CodexExe <path>] [-TimeoutSec <s>]— síncrono (prompt → texto). Prompt via stdin; resposta final pelooutput-last-message.-MessagePathlê o prompt de arquivo (exclusivo com-Message; dispensa(Get-Content)inline no chamador); stdin-based, então não está sujeito ao teto ~32KB.Start-CodexJob.ps1 [-Message <prompt> | -MessagePath <arquivo>] [-Model <m>] [-Oss] [-LocalProvider <p>] [-Profile <id>] [-Cd <dir>] [-CodexExe <path>] [-NoWatcher] [-TempDir <path>] [-KeepDays <n>]— assíncrono; retorna{jobId, pid, stream, lastmsg, result, watcher}; abre janela de acompanhamento por padrão.-MessagePathexclusivo com-Message(o texto do prompt segue persistido emrequest.json/stdin.txt).Watch-CodexJob.ps1 -JobId <guid> -ProcessId <pid> [-TempDir <path>] [-IntervalSeconds <1-30>] [-SilenceThresholdSeconds <30-3600>]— monitor incremental do stream--json; grava<GUID>.result.jsonao fim (status,finalText,error,inputTokens,outputTokens).CodexCliSupport.ps1(dot-source) — descoberta fail-closed docodex.execompatível (app desktop sob%LOCALAPPDATA%\OpenAI\Codex\bin, maior versão; ignora o shim npm do PATH, rejeitado para GPT-5.5).
Nota de default de modelo: Invoke-OpenCode.ps1 e Invoke-Codex.ps1 seguem o mesmo contrato.
Se -Model for omitido, o adapter não força modelo e deixa o default da ferramenta/config valer.
gpt-5.5 permanece apenas como exemplo/sugestão de revisor Codex no painel reforçado, não como
modelo fixado pelo adapter.
Backend Claude Code (claude -p, Opus 4.8 por padrão, externo Anthropic):
Invoke-ClaudeCode.ps1 [-Message <prompt> | -MessagePath <arquivo>] [-Model <m>] [-PermissionMode <mode>] [-Tools <list>] [-MaxTurns <n>] [-Cd <dir>] [-ClaudeExe <path>] [-TimeoutSec <s>]— síncrono (prompt → texto). Prompt via stdin (-MessagePathlê de arquivo, exclusivo com-Message; stdin-based, sem o teto ~32KB); por padrão usa consulta curta restrita (PermissionMode=plan,Tools=Read,Glob,Grep, sem persistência de sessão).-MaxTurnsé aplicado somente quando a versão local do Claude Code expõe--max-turns.Start-ClaudeCodeJob.ps1 [-Message <prompt> | -MessagePath <arquivo>] [-Model <m>] [-PermissionMode <mode>] [-Tools <list>] [-MaxTurns <n>] [-Cd <dir>] [-ClaudeExe <path>] [-NoWatcher] [-TempDir <path>] [-KeepDays <n>]— assíncrono; retorna{jobId, pid, stream, result, watcher}; abre janela de acompanhamento por padrão.-MessagePathexclusivo com-Message(o texto do prompt segue persistido emrequest.json/stdin.txt).-MaxTurnsé aplicado somente quando a CLI suportar a flag.Watch-ClaudeCodeJob.ps1 -JobId <guid> -ProcessId <pid> [-TempDir <path>] [-IntervalSeconds <1-30>] [-SilenceThresholdSeconds <30-3600>]— monitor incremental do stream--output-format stream-json; grava<GUID>.result.jsonao fim (status,finalText,error).ClaudeCodeCliSupport.ps1(dot-source) — descoberta fail-closed doclaude.exe, validação de versão/flags mínimas e extração de erros.
Backend GitHub Copilot CLI (copilot -p, externo GitHub Copilot):
Invoke-Copilot.ps1 [-Message <prompt> | -MessagePath <arquivo>] [-Model <m>] [-Cd <dir>] [-CopilotExe <path>] [-TimeoutSec <s>]— síncrono (prompt → texto). Usa--no-custom-instructions,--disable-builtin-mcps,--available-tools=e JSONL para consulta curta sem ferramentas disponíveis;--allow-all-toolspermanece porque o CLI exige aprovação automática em modo não interativo.-MessagePathlê o prompt de arquivo (exclusivo com-Message; elimina o(Get-Content)inline), mas é argument-based — o prompt segue no argv, então não levanta o teto ~32KB; um guard fail-closed ($MaxArgvPromptChars = 30000, heurístico em chars) recusa prompts grandes comBLOCK.CopilotCliSupport.ps1(dot-source) — descoberta fail-closed docopilot, validação de versão/flags mínimas e extração de resposta do JSONL.
Backend Gemini CLI (gemini -p, externo Google):
Invoke-Gemini.ps1 [-Message <prompt> | -MessagePath <arquivo>] [-Model <m>] [-ApprovalMode plan] [-Cd <dir>] [-GeminiExe <path>] [-TimeoutSec <s>]— síncrono (prompt → texto). Usa--approval-mode plane--output-format json; o adapter bloqueia modos diferentes deplan.-MessagePathlê o prompt de arquivo (exclusivo com-Message; elimina o(Get-Content)inline), mas é argument-based — o prompt segue no argv, então não levanta o teto ~32KB; um guard fail-closed ($MaxArgvPromptChars = 30000, heurístico em chars) recusa prompts grandes comBLOCK.GeminiCliSupport.ps1(dot-source) — descoberta fail-closed dogemini, validação de versão/flags mínimas e extração de erros.
Latência por provedor: modelos externos OAuth (openai/*, Codex externo; anthropic/*,
Opus 4.8 do Claude Code; github-copilot/*; google/*) podem passar de 180s — ajustar -TimeoutSec; ollama-cloud/* e
opencode-go/* costumam responder mais rápido.
Em painéis com múltiplos revisores ollama-cloud/*, limitar o paralelismo desse provider a
3 chamadas simultâneas e enfileirar os demais. Em teste real, disparar 4 modelos
ollama-cloud/* ao mesmo tempo produziu ausência de parecer utilizável em um deles; rodado
sozinho, o mesmo modelo respondeu normalmente. Portanto, falha sem texto nesse cenário deve ser
tratada primeiro como possível saturação de concorrência do provider, não como evidência de baixa
qualidade do modelo. Antes de fechar um revisor preferido como error por falha sem texto colhida
em lote concorrente, redispará-lo uma única vez isolado (single-flight, fora da concorrência,
após a fila de 3 + enfileirar): se responder, vale o parecer; se falhar de novo sozinho, aí sim
error/noResponse. Não marcar error no primeiro BLOCK sem texto vindo do paralelo, nem virar
laço de redisparo. Escopo: só falha sem texto em lote concorrente — não gateDeny/gateAsk/timeout
legítimo.
Núcleo backend-agnóstico:
Resolve-OpenCodeModelLocality.ps1,Resolve-CodexModelLocality.ps1,Resolve-ClaudeCodeModelLocality.ps1,Resolve-CopilotModelLocality.ps1,Resolve-GeminiModelLocality.ps1,Resolve-LlmDelegationPolicyPath.ps1(resolve o caminho do arquivo de política: nome canônicollm-delegation-policy.jsoncom fallback ao legadoopencode-delegation-policy.json;statusnew|legacy|both|none) eResolve-LlmDelegateAuthorization.ps1(ver## ANATOMIAe## CONFIDENCIALIDADE).
Sondagem de capacidade (para a oferta de revisão por pares — ver 15-revisao-por-pares.md):
Build-LlmDelegateCapabilityManifest.ps1 [-OutputPath <json>] [-SnapshotPath <json>] [-OpenCodeConfigPath <opencode.json>] [-CodexConfigPath <config.toml>]— sonda os backends instalados e enumera modelos disponíveis (opencode viaopencode.json, Codex viaconfig.toml; Claude Code/Copilot/Gemini sem enumeração nativa), reusando osResolve-*ModelLocalitypara a localidade. Grava o manifesto de capacidade sanitizado machine-level (default%LOCALAPPDATA%\xpz-llm-delegate\capabilities.json; sócanonicalModel/backend/locality/reasonCode/sourceKind/schemaVersion/generatedAt+lastHealthCheckseparado — nunca token, chave, baseURL, header, path de config, prompt ou política) e, com-SnapshotPath, um snapshot por-KB (cache re-derivável). É dica de oferta: o gate (Resolve-LlmDelegateAuthorization.ps1) não o consome — reavalia destino e sensibilidade sempre. Self-testTest-LlmDelegateCapabilityManifestSelfTest.ps1.Set-LlmDelegatePreferredReviewers.ps1 -ReviewersJson <json> [-OutputPath <json>]— persiste a curadoria de revisores preferidos do usuário em%LOCALAPPDATA%\xpz-llm-delegate\preferred-reviewers.json(machine-level), schema de 2 eixos por revisor:targetModelKey(chave de destino → política/autorização) +invokeArgssanitizado (model/profile/oss/localProvider; nunca token/baseURL/header/path). Descarta com aviso modelo de veto duro (Mistral Large 3, Nemotron 3 Ultra). O menu de escolha o agente monta comopencode models(catálogo opencode) +capabilities.json/defaults dos demais, mas deve perguntar em termos reconhecíveis de ferramenta e assinatura disponível (Claude Code,opencode/Ollama Cloud,Codex,Copilot,Gemini, subagente nativo); o script só persiste a seleção.Resolve-LlmDelegatePreferredReviewers.ps1 [-PreferredPath <json>] [-CapabilitiesPath <json>]— lê a curadoria e a cruza comcapabilities.json(availableInManifest, best-effort), devolvendo a composição sugerida do painel. Sem arquivo →hasPreferences=false(oferta cai no comportamento atual). Invariante: preferência ≠ autorização — não consome o manifesto como verdade do gate; oResolve-LlmDelegateAuthorization.ps1reavalia por revisor no envio. Self-testTest-LlmDelegatePreferredReviewersSelfTest.ps1.Resolve-LlmDelegatePanelDiversity.ps1 -CandidatesJson <json> [-Floor <n>] [-AuthorFamily <fam>]— avalia (consultivo) o piso de diversidade do painel (≥2 famílias distintas = provider de destino) a partir dos candidatos + vereditos do gate; devolvepanelReady/needsBatchAuthorization(comaskToAuthorize) /insufficientDiversity(comfallbackLabel"segunda opinião (N)"). Impede o painel colapsar para uma voz em silêncio. Não decide autorização (o gate é soberano). Inclua todos os revisores como candidatos — inclusive subagentes nativos, representados pela família do orquestrador (ex.:anthropic/claude-opus-4-8quando o orquestrador é Claude) —, senão o piso não cobre a montagem por subagente nativo (um painel só de nativos = 1 família). Self-testTest-LlmDelegatePanelDiversitySelfTest.ps1.Resolve-LlmDelegatePeerReviewCloseout.ps1 -HadPreferredReviewers <true|false> -ManualReviewerSelection <true|false> [-PreferredReviewersOfferState not_made|offered|accepted|declined|deferred|not_applicable] [-SelectedReviewersJson <json>] [-PreferredReviewerStatesJson <json>] [-DiversityState <state>] [-RoundId <id>] [-VNextState notProduced|pendingResubmission|resubmitted|resubmissionDeclinedByHuman] [-ResubmissionDeclinedBy <quem>] [-ResubmissionDeclineReason <motivo>]— verifica o fechamento da revisão por pares: se não haviapreferred-reviewers.jsone houve escolha manual de revisores, bloqueia o recibo final enquanto a oferta de salvar essa seleção não tiver sido feita; se haviapreferred-reviewers.json, bloqueia quando falta estado auditável para os revisores preferidos da rodada ou quando há estado incompleto (gateAllow,dispatched,enqueued). Eixo de estado da vN+1 (Achado A):-VNextState pendingResubmission(vN+1 autorada e não re-submetida) bloqueia (vnext-pending-resubmission);resubmissionDeclinedByHumanbloqueia se faltar-ResubmissionDeclinedBy,-ResubmissionDeclineReasonou-RoundId(vnext-resubmission-decline-unaudited);resubmitted/notProducedsão neutros; ovNextStateé sempre ecoado noreceiptAddendum(inclusivenotProduced). O script é stateless — a monotonicidade/append-only entre chamadas é do orquestrador + recibo, não do script (à prova de silêncio, não de fabricação). DevolvecloseoutReady,blockingReasons,preferredReviewerStates,vNextState,requiredUserPromptereceiptAddendum. Não grava preferência, não decide autorização e não recalcula diversidade; a gravação continua emSet-LlmDelegatePreferredReviewers.ps1, a autorização no gate e o piso emResolve-LlmDelegatePanelDiversity.ps1.-HadPreferredReviewers/-ManualReviewerSelectionrecebem a stringtrue/false(validada porValidateSet), não o literal$true/$false: viapwsh -Filechamado de Bash, tokens nus$true/$falseexpandem para vazio antes dopwsh. Self-testTest-LlmDelegatePeerReviewCloseoutSelfTest.ps1.
Harness de disparo do painel (orquestração mecânica — ver ### Harness de disparo do painel):
Invoke-LlmDelegatePanelDispatch.ps1 -ManuscriptPath <arq> -ReviewersJson <arq|inline> -PayloadSensitivity <public|kb-sensitive> [-RoundId <id>] [-Cd <dir>] [-ParallelKbRoot <dir>] [-PolicyPath <json>] [-TempDir <dir>] [-OllamaConcurrency <1-16>](+ TEST-ONLY-OpenCodeConfigPath/-CodexConfigPath/-BackendExeMap) — harness MECÂNICO de despacho+coleta: por revisor roda o gate (sem autorizar), despacha osallowaos adaptersInvoke-*.ps1em paralelo (ForEach-Object -Parallel -ThrottleLimit 8+SemaphoreSlim($OllamaConcurrency)via$using:só paraollama-cloud/*), classifica o resultado de forma estrutural e emitepanel-summary.json(1 linha de stdout,Kind/SchemaVersionPascalCase) +manifest.json+ ledger por estado (.verdict/.error/.state) em<TempDir>/<RoundId>/. Não injeta subagente nativo, não calcula piso/closeout/triagem/convergência/autorização — isso é do orquestrador. Self-testTest-InvokeLlmDelegatePanelDispatchSelfTest.ps1.
Três artefatos distintos (não confundir): política por-KB (llm-delegation-policy.json, autorização durável, raiz da pasta paralela) ≠ capacidade (capabilities.json, probe do instalado, machine-level) ≠ preferência (preferred-reviewers.json, curadoria do usuário, machine-level). A curadoria é ofertada, nunca gravada automaticamente, em quatro momentos: (a) no 1º uso de revisão por pares sem lista — pergunta just-in-time antes de oferecer painel e, depois que o usuário escolher revisores para a rodada, oferta separada para salvar essa seleção; (b) opt-in na xpz-skills-setup (setup de máquina); (c) recalibração sob demanda ou por defasagem (updatedAt); (d) quando uma seleção manual recorrente divergir da lista existente e o usuário pedir ou confirmar recalibração. Sem lista, o agente não deve presumir assinatura de Gemini/Copilot/Codex cloud nem ignorar Claude Code/opencode; pergunta ao usuário quais revisores estão disponíveis/preferidos e então roda o gate por destino.
Quatro eixos na seleção de revisores (não confundir):
| Eixo | Pergunta | Quem responde |
|---|---|---|
| Capacidade detectada | O backend está instalado? Quais modelos aparecem? | capabilities.json e sondas locais |
| Assinatura/login | O usuário tem conta funcional nesse serviço? | Só o humano ou uma preferência já registrada |
| Preferência | O usuário quer usar esse revisor? | preferred-reviewers.json ou confirmação explícita |
| Autorização por KB | O payload pode ir para esse destino? | llm-delegation-policy.json + gate |
Nenhum eixo substitui outro. Um backend instalado sem assinatura/login funcional não é revisor
disponível. Um allow-external na política autoriza envio de dados para aquele destino, mas
não escolhe revisor nem prova preferência humana. Um ask indica autorização pendente, não
convite obrigatório ao painel. A preferência é humana e nunca deve ser inferida só de
capacidade detectada ou autorização por KB. Onde cada eixo é mantido (não colapsar num campo
só): capacidade vem do capabilities.json/sondas; assinatura/preferência só do humano ou do
preferred-reviewers.json; autorização do gate (Resolve-LlmDelegateAuthorization.ps1) por
destino. Nenhum componente decide pelo outro.
Composição toda-externa em contexto kb-sensitive (Achado B). A lista preferida é
machine-level e contexto-agnóstica: em sessão dentro de pasta paralela de KB (payload
kb-sensitive), uma composição preferida toda-externa manda conteúdo sensível para fora a
cada revisor. O gate (Resolve-LlmDelegateAuthorization.ps1) continua soberano por destino,
mas, antes de despachar, o orquestrador deve avisar que a composição é toda-externa e
perguntar ao humano se quer incluir um revisor local. Se não houver revisor local
disponível, parar e reportar — não escolher externo por inércia/falta de alternativa. Isto
não veta envio externo: o humano ainda pode autorizá-lo e o gate por destino continua soberano;
o ponto é não proceder por inércia sem o nó humano, não proibir externo autorizado. Descoberta
de local não por Get-Command como caminho principal (ver ### Protocolo de descoberta e bootstrap de capacidade).
Apresentação do override e camadas permitido≠prudente (reforço do Achado B). Quando a
composição é toda-externa e não há revisor local, o default declarado é parar/incluir
local; seguir só com externo é override consciente, válido apenas por autorização textual
explícita do humano — ausência de veto não é autorização. É proibido apresentar "seguir
só externo" como opção neutra co-igual à de incluir local. O gate de autorização responde
"é permitido enviar?", nunca "é prudente/recomendado?": allow autoriza, mas nunca é,
por si, recomendação, e a cautela do Achado B é camada separada que allow não dispensa;
gate=deny invalida o override (gate soberano) e gate=allow não substitui o aviso de risco
abaixo. O default é de apresentação, não bloqueio absoluto: o humano pode pré-autorizar
externo numa frente anterior, mas a pré-autorização cobre só o modo (o override do Achado B),
não dispensa o aviso de risco por destino abaixo (eixos ortogonais) e só vale se precedida de
aviso equivalente. Não enquadrar custo/latência do painel inteiro como argumento para
reduzi-lo a subconjunto, salvo pedido explícito do humano (o piso de famílias é mínimo de
validade, não alvo).
Aviso de risco proporcional antes de envio externo kb-sensitive. Quando o payload é
kb-sensitive (definição canônica acima — não redefinir) e o destino é externo, antes de
enviar, na mesma mensagem do pedido de autorização, o agente enumera (não rotula):
(i) o quê concretamente sai — conteúdo enumerado (ex.: "estrutura de transações + ~430
atributos do schema da KB riskNotice{what, destinations[], irreversibility} e, no override,
overrideOfAchadoB (consciousOverride quando o humano autoriza externo sem local;
notApplicable quando há revisor local em uso), humanAuthorizer + authorizationTextRef
(a fala que autorizou, não só by=human) e localReviewerStatus
(noneAvailable/unavailable/declined/inadequate). consciousOverride exige
localReviewerStatus resolvido — incompatível com verificação omitida.
Quando preferred-reviewers.json existe, ele alimenta a lista preferida de candidatos do
painel; não é mera lista opcional para o agente escolher o mínimo, nem autorização para envio.
O orquestrador deve rodar gate por revisor preferido e passar a lista completa de candidatos
preferidos + vereditos para Resolve-LlmDelegatePanelDiversity.ps1, não um subconjunto
auto-selecionado. Revisor preferido com allow deve ser despachado quando a rodada o alcança,
salvo decisão humana explícita de reduzir o painel; ask deve ser apresentado ao humano em lote
quando necessário; deny, indisponibilidade, timeout, erro técnico ou interrupção por primeiro
gap não autorizam omitir os demais em silêncio — cada preferido recebe estado no recibo
(responded, noResponse, timeout, error, gateAsk, gateDeny, unavailable,
skippedByHumanDecision, stoppedOnGap). responded exige parecer utilizável: um retorno
off-task/sem-parecer/vazio ou on-task porém substantivamente vazio/raquítico (terminou em stop mas não se posiciona sobre o manuscrito) é noResponse, não
responded — senão o recibo infla o aproveitamento e um off-task pode satisfazer falsamente o
piso de "≥2 famílias efetivamente consultadas" (ver 15-revisao-por-pares.md,
recibo). Preferência continua subordinada à política de papel e
ao gate.
Sem preferred-reviewers.json, o agente não deve recomendar composição padrão com Gemini,
Copilot, Codex cloud ou qualquer externo só porque o backend foi detectado ou o gate devolveu
allow/ask. A pergunta correta é de calibração: quais ferramentas o usuário tem e quer usar.
Quando houver contexto conversacional explícito (por exemplo, o usuário já disse que tem
Claude Code e opencode/Ollama Cloud, ou que não tem Gemini), esse contexto prevalece sobre
inventário genérico.
Formato obrigatório sem preferred-reviewers.json
Quando Resolve-LlmDelegatePreferredReviewers.ps1 devolver hasPreferences=false, a resposta
ao usuário deve seguir este formato enxuto antes de qualquer envio:
- Declarar que não há lista de revisores preferidos configurada.
- Declarar a classe do payload (
publicoukb-sensitive). - Perguntar: "Quais ferramentas/modelos você tem e quer usar como revisores?"
- Citar exemplos de ferramentas em linguagem humana (
Claude Code,opencode/Ollama Cloud,Codex,Copilot,Gemini, subagente nativo), mas filtrar qualquer ferramenta que o usuário já tenha descartado na conversa corrente. - Declarar que inventário detectado e veredito de autorização são diagnóstico, não preferência: o gate será rodado por destino depois da escolha.
É proibido incluir recomendação de composição nesse ponto, em especial frases como "uma opção
objetiva seria", "o caminho mais simples seria" ou "eu sugiro X + Y", quando houver revisor externo
sem preferência registrada. Se for útil citar inventário, rotular como diagnóstico separado e sem
promover itens detectados a opção recomendada. Não usar allow-external ou ask como argumento
para escolher revisor; autorização decide envio, não preferência.
Protocolo de descoberta e bootstrap de capacidade
Para descobrir os revisores disponíveis, a ordem é: (1) capabilities.json (manifesto
sanitizado machine-level) → (2) Resolve-*ModelLocality por backend → (3) opencode models
(catálogo opencode). Get-Command e sondas de presença (--version/--help) são só
diagnóstico auxiliar de último recurso, nunca prova de assinatura/preferência (não as use como
caminho principal).
Frescor do capabilities.json é pelo campo generatedAt (carimbo real do manifesto —
não updatedAt, que pertence ao preferred-reviewers.json). Os três artefatos têm carimbos
distintos: capabilities.json = generatedAt; snapshot por-KB = snapshotAt/sourceGeneratedAt;
preferred-reviewers.json = updatedAt. Manifesto defasado não é verdade do gate — é dica
best-effort; ofereça regerar (Build-LlmDelegateCapabilityManifest.ps1, opt-in) e use sondas
vivas para desempatar.
Bootstrap quando capabilities.json não existe (máquina virgem) — não falhar duro, não criar
stub silencioso, não fabricar assinatura: (1) Resolve-LlmDelegatePreferredReviewers.ps1 devolve
hasPreferences=false → perguntar ao usuário (formato acima); (2) resolver capacidade por sondas
vivas só-para-a-rodada (opencode models + Resolve-*ModelLocality do backend escolhido); (3)
oferecer gerar o manifesto opt-in — nunca gravá-lo automaticamente. Fim da cadeia: se
nenhuma fonte resolver capacidade, perguntar ao humano/parar — não inventar composição.
Fallback de silêncio humano: se hasPreferences=false e o humano não responde à pergunta
de calibração, não prosseguir para revisor externo por heurística; parar (ou só local) e
registrar o bypass no recibo/livro-razão. Sem resposta ≠ autorização implícita.
Persistência após escolha de revisores
Quando não houver preferred-reviewers.json e o usuário escolher revisores para a rodada, o
agente deve tratar duas persistências como decisões independentes:
- Autorização por KB/projeto: se o payload for
kb-sensitive, perguntar se o conteúdo pode ser enviado aos destinos externos emask. Se o usuário quiser persistir essa autorização, gravarllm-delegation-policy.jsonna raiz da pasta paralela da KB/projeto. - Curadoria de revisores preferidos: oferecer salvar a seleção que o usuário já fez como
preferência machine-level em
%LOCALAPPDATA%\xpz-llm-delegate\preferred-reviewers.json, viaSet-LlmDelegatePreferredReviewers.ps1. Essa oferta não bloqueia a rodada: se o usuário recusar ou não responder, seguir com a seleção ad-hoc já autorizada para a rodada.
Preferência ≠ autorização. Persistir llm-delegation-policy.json autoriza envio para destinos,
mas não escolhe revisores nem prova preferência humana. Persistir preferred-reviewers.json
facilita a oferta de painel futuro, mas não substitui o gate por KB/projeto. Se já existir
preferred-reviewers.json e o usuário fizer uma escolha manual diferente para uma rodada, tratar
como override ad-hoc: não sobrescrever a lista automaticamente; só oferecer recalibrar se o usuário
pedir, se a divergência parecer recorrente ou se ele confirmar explicitamente.
Harness de disparo do painel (Invoke-LlmDelegatePanelDispatch.ps1)
É o «harness de disparo» previsto em 15-revisao-por-pares.md (## Futuros): mecaniza o
despacho+coleta que antes era ad-hoc. A fronteira orquestrador ↔ harness é estrita:
ORQUESTRADOR (fora do harness) │ HARNESS (Invoke-LlmDelegatePanelDispatch.ps1)
───────────────────────────────────────────── │ ─────────────────────────────────────────────
injeta subagente nativo │ por revisor: modelo efetivo + fail-closeds
piso de diversidade (Resolve-...PanelDiversity)│ gate por revisor (Resolve-...Authorization), sem autorizar
closeout (Resolve-...PeerReviewCloseout) │ despacho CONCORRENTE dos allow (ForEach-Object -Parallel
triagem do 1º gap / convergência / vN+1 │ -ThrottleLimit 8 + SemaphoreSlim só p/ ollama-cloud/*)
autorização dos `ask` (lote ao humano) │ classificação ESTRUTURAL do resultado (sem ler a prosa)
recibo humano + livro-razão │ ledger por estado + panel-summary.json + manifest.json
reclassificação responded→noResponse (off-task)│ estados emitidos ⊆ {responded,error,unavailable,timeout,
re-despacho single-flight do ollama que falhou │ gateAsk,gateDeny}
- Modelo efetivo: opencode =
invokeArgs.modelou otargetModelKeyde entrada (o resolvedor opencode exige-Model; o gate recebe o mesmo valor); codex =invokeArgs.modelou, se ausente, gate sem-Model→ último segmento dotargetModelKeyretornado; claude-code/copilot/gemini =invokeArgs.modelobrigatório (ausente →state=errorfail-closed).targetModelKeynulo onde exigido (opencode/codex) →state=error. respondedé MECÂNICO (texto não-vazio), não «parecer válido»: o harness não inspeciona o conteúdo. A reclassificaçãoresponded→noResponse(revisor off-task ou on-task raquítico) é post-hoc do orquestrador antes do closeout (15-revisao-por-pares.md,## Recibo e livro-razão) — um off-task ou parecer raquítico não soma para o piso.- Contenção = trava fail-closed PER-BACKEND (Posição B, decisão de segurança): as chaves de contenção do backend que as aceita — claude-code
{permissionMode,tools,maxTurns}, opencode{agent}, gemini{approvalMode != plan}— são recusadas (securityBlockedArgs) e não repassadas ao adapter; o despacho segue com os defaults seguros do adapter. O harness nunca expõe nem relaxa contenção.approvalMode=plan(gemini, o default) →droppedArgssilencioso; codex/copilot não têm parâmetro de contenção (chave estranha →droppedArgs). - opencode só-
publicno v1: opencode emkb-sensitive→unavailable(sem gate/despacho); o confinamento do agente custom fica para a frente 999 «agente reviewer sem execução/escrita». O adapter opencode não tem-Cd(por isso nunca o recebe); os demais (codex/claude-code/gemini/copilot) recebem-Cdpor precedência (explícito →ParallelKbRootemkb-sensitive→ cwd empublic) com fail-closed quandokb-sensitivee faltam ambos. - single-flight DIFERIDO (decisão II-b): uma falha concorrente de
ollama-cloud/*viraerror+ ledger cru +concurrencySaturationWarningpor stderr; a recuperação automática depende do contrato de saída tipado dos adapters (frente 999) — o orquestrador pode redisparar isolado manualmente. - Disciplina de stdout: o harness é processo filho;
panel-summary.jsoné a única linha de stdout ([Console]::Out); todo texto humano sai por[Console]::Error(lição doSync-GeneXusXpzToXml:Write-Host/Write-Warning/Write-Informationvazam para o stdout capturado). O chamador captura stdout e stderr separadamente; redirecionar stderr→stdout corromperia o JSON. - NÃO refatorar os 6 adapters por esta frente: o status tipado dos adapters é frente própria no 999.
Forma canônica de invocação dos adapters
A allowlist do harness (Claude Code, Codex, OpenCode, Cursor) casa comandos atômicos, não comandos compostos. Cada variante de forma exige uma entrada de allowlist distinta — deriva que, além de incomodar, gera prompt de autorização desnecessário quando o match literal falha.
Princípio: comando atômico, prompt sempre por -MessagePath <arquivo>, zero aspas embutidas para o prompt. A raiz do atrito é prompt inline + múltiplos segmentos entre aspas no mesmo comando quebrando o match literal da allowlist — -MessagePath + comando atômico elimina isso.
Forma por ferramenta (cada uma casa a sua família de entrada na allowlist):
- Pela ferramenta Bash (forma primária), com
cwdna raiz do repo, path relativo:pwsh -NoProfile -File scripts/<Adapter>.ps1 -MessagePath <arquivo> [demais parâmetros do adapter]— casa a entradaBash(pwsh -NoProfile -File scripts/*). - Pela ferramenta PowerShell (fallback), path absoluto:
& "<abs>\scripts\<Adapter>.ps1" -MessagePath <arquivo> [demais parâmetros do adapter]— casa as entradasPowerShell(& "<repo>\scripts\*" *).
Importante (cobertura por ferramenta): o path relativo é a forma coberta via Bash; o fallback PowerShell é coberto na forma de path absoluto. Não existe entrada ampla cobrindo path relativo via PowerShell — então não use
& "scripts\<Adapter>.ps1"(relativo, via PowerShell) como forma canônica. Manter cada forma na sua ferramenta evita recair em variação não coberta.
Síncrono vs assíncrono (parâmetros próprios do adapter):
- Síncrono
Invoke-*:-MessagePath <arquivo> [-Model <m>] [-TimeoutSec <s>]. - Assíncrono
Start-*Job(os existentes: opencode, Codex, Claude Code — Gemini/Copilot não têm job):-MessagePath <arquivo> [-Model <m>] [-NoWatcher] [-TempDir <dir>] [-KeepDays <n>]—-TimeoutSecnão se aplica aos jobs. A regra-MessagePath/atômico vale igual para os dois.
Arquivo de -MessagePath: preferir caminho sem espaços, sob o Temp do usuário (%LOCALAPPDATA%\Temp, já allowlistado para escrita) — fecha o ciclo escrita+leitura sem prompt; se o caminho exigir aspas, um único par e nada de prompt inline.
-Cd (quando o adapter suportar): Codex, Claude Code, Copilot e Gemini aceitam -Cd; opencode NÃO tem -Cd. Quando suportado, omitir -Cd se o cwd já é a raiz; preferir apontar o diretório pelo parâmetro workdir da própria ferramenta em vez de passar -Cd no comando; nunca -Cd como segundo segmento entre aspas (foi exatamente um -Cd "<path>" somado a um prompt inline entre aspas que produziu o caso real de 2026-06-21, ver abaixo).
Ressalva ~32KB (cross-reference): -MessagePath elimina a substituição de comando inline ((Get-Content) / "$(cat ...)") no chamador em todos os adapters; mas só os stdin-based (Codex, opencode, Claude Code) também movem o prompt para fora do argv (escapam do teto). Nos argument-based (Gemini/Copilot) o adapter lê o arquivo e repassa o prompt no argv interno — o teto ~32KB permanece, com o guard fail-closed de 30000 chars ativo. -MessagePath não levanta o teto nesses dois. Ver a seção de limite no SKILL.md para detalhe.
O caso real que motivou o item: em 2026-06-21, Invoke-Codex.ps1 foi chamado como:
& "<abs>\Invoke-Codex.ps1" "<prompt>" -Model gpt-5.5 -Cd "<abs>" -TimeoutSec 420
...e promptou apesar de existirem entradas PowerShell(& "…\scripts\*"). A causa foi as aspas embutidas — prompt inline como segmento posicional + -Cd "<path>" no mesmo comando — quebrando o match literal da allowlist. Foi uma chamada da mesma família PowerShell contra entradas PowerShell existentes, não um descasamento de ferramenta. A forma canônica (prompt por -MessagePath, comando atômico, zero aspas embutidas) corrige exatamente essa causa. A regra "manter cada forma na sua ferramenta" é um cuidado preventivo adicional.
Nota não-normativa de allowlist: como referência para quem configura uma máquina nova, o padrão de entrada ampla que cobre a forma canônica é:
Bash(pwsh -NoProfile -File scripts/*)PowerShell(& "<repo>\scripts\*" *)
Esses padrões são exemplo informativo — não são arquivo versionado e não fazem parte do setup automático.
MANUSCRITO/PROMPT PARA REVISORES
Ao montar o manuscrito/prompt de revisão por pares, não embutir como fatos conclusões que a
revisão deve validar. Descrever evidências observadas e hipóteses separadamente. Exemplos de
redação a evitar quando ainda são a matéria da revisão: "identificador universal", "sequencial
autogerado" ou "padrão da KB" sem fonte normativa ou validação anterior. Preferir formulações
auditáveis, como "o XML observado tem AUTONUMBER=True", "há N usos encontrados" e "a hipótese
do plano é que a descrição curta deva comunicar X". O revisor recebe o manuscrito para confirmar
ou refutar, não para ratificar conclusão já embalada como verdade.
Blinde o papel do revisor. O prompt vai a backends agênticos (opencode, Codex, Claude Code)
que podem ler o manuscrito como ordem para executar o plano ou conduzir eles mesmos uma
revisão por pares — risco agudo quando o manuscrito é autorreferente (a própria metodologia).
Instrua de forma imperativa que o destinatário é um revisor: deve emitir o próprio parecer
(concorda/revisa/rejeita, com justificativa e gaps priorizados) e não executar, montar painel,
delegar nem assumir o papel do orquestrador. Um retorno que assume a tarefa em vez de opinar
registra-se como noResponse, nunca responded.
PATH RESOLUTION: este SKILL.md fica numa subpasta sob a raiz; os scripts ficam em
../scripts/ relativos a esta pasta. Resolver caminhos a partir da raiz do repositório.
WORKFLOW (uma delegação)
- Confirmar o gatilho humano: o usuário pediu, ou aprovou explicitamente uma sugestão de delegar. Sem isso, não delegar.
- Classificar a tarefa: é delegável (mecânica/segunda-opinião) ou é juízo GeneXus? Se for
juízo, não delegar (ver
## O QUE NÃO DELEGAR). - Classificar o payload:
public(texto do repo público, molde sanitizado) oukb-sensitive(conteúdo de pasta paralela). Na dúvida, tratar comokb-sensitive. 3a. Em revisão por pares, antes de escolher backends, resolverpreferred-reviewers.json. Se não houver lista (hasPreferences=false), perguntar ao usuário quais ferramentas/modelos ele tem disponíveis ou prefere (Claude Code,opencode/Ollama Cloud,Codex,Copilot,Gemini, subagente nativo). A pergunta é de preferência e assinatura/login, não de inventário: não substituir por enumeração técnica de providers nem por menu de tudo que está instalado. Backend detectado sem preferência deve ser apresentado como "detectado; confirme se quer usar"; não sugerir composição padrão com externo sem preferência confirmada. Seguir o formato obrigatório da seção acima. Depois que o usuário escolher revisores para a rodada, oferecer salvar essa seleção já feita empreferred-reviewers.json, separadamente da autorização por KB; não bloquear a rodada se o usuário não quiser salvar curadoria. Subagente nativo pode entrar no painel, mas conta como a família do orquestrador e não substitui uma família externa para cumprir o piso. 3b. Em revisão por pares, antes de emitir recibo final ou dizer que a rodada foi concluída, rodarResolve-LlmDelegatePeerReviewCloseout.ps1com o estado real da rodada. SecloseoutReady=false, apresentarrequiredUserPromptao usuário e não encerrar a rodada como revisão por pares até a oferta ser feita ou registrada como aceita, recusada ou adiada. Quandopreferred-reviewers.jsonjá existia, passar-PreferredReviewerStatesJsoncom o estado final de cada preferido da rodada; não usar o piso mínimo (≥2 famílias) como critério para omitir preferidos despacháveis sem estado auditável. Eixo da vN+1 (Achado A): no momento em que você autora a versão consolidada (vN+1), passe-VNextState pendingResubmission— o closeout bloqueia o fechamento até a vN+1 serresubmitted(re-submetida ao painel) ou o humano declinar de forma auditável (-VNextState resubmissionDeclinedByHuman -ResubmissionDeclinedBy <quem> -ResubmissionDeclineReason <motivo> -RoundId <rodada>). A transição só acontece por nova invocação do closeout com o novo-VNextState; ovNextStateentra no recibo mínimo (ver15-revisao-por-pares.md). - Escolher o backend e o modelo. Rodar
Resolve-LlmDelegateAuthorization.ps1com modelo + sensibilidade +-Backend opencode|codex|claude-code|copilot|gemini(em pasta paralela, passar-ParallelKbRoot <raiz>para descobrir a política pelo nome canônico com fallback ao legado, ou-PolicyPathpara um caminho explícito; compolicyNameStatuslegacy/both, avisar o usuário que o nome legado está em uso e oferecer renomear).allow→ seguir; anunciar o destino ao usuário (usetargetModelKeydo resultado).deny→ não enviar; informar o motivo e oferecer alternativa local.ask→ pedir autorização explícita ao usuário; se autorizado, oferecer persistir a escolha nollm-delegation-policy.json(liberação durável; nome legadoopencode-delegation-policy.jsonainda aceito).
- Invocar o adapter do backend escolhido: opencode (
Invoke-OpenCode.ps1/Start-OpenCodeJob.ps1), codex (Invoke-Codex.ps1/Start-CodexJob.ps1), Claude Code (Invoke-ClaudeCode.ps1/Start-ClaudeCodeJob.ps1), Copilot (Invoke-Copilot.ps1) ou Gemini (Invoke-Gemini.ps1) — síncrono (curto) ou assíncrono (longo, quando o backend tiver job). - Validar a saída com o agente forte antes de usá-la. Não confiar em timestamps/fatos reportados pelo subagente.
LIMITE CONHECIDO — OPENCODE COM MODELO LOCAL PEQUENO
O backend opencode é agêntico: cada chamada carrega system prompt + schemas de todas as
ferramentas + o que estiver em instructions da config do opencode (ex.: um AGENTS.md global
extenso). Esse prompt por chamada pode passar de ~16k tokens.
Falhas do CLI antes da chamada ao modelo com mensagens de SQLite/PRAGMA/CREATE TABLE indicam
estado local corrompido do opencode, não erro do adapter. Recuperação operacional conservadora:
fechar o OpenCode desktop e renomear opencode.db* na pasta de dados do opencode para backup,
preservando arquivos de autenticação/configuração.
Consequência em GPU de pouca VRAM (medido empiricamente em RX 580 8 GB, Vulkan, com placement 100% GPU e sem spill para RAM/compartilhada):
- modelo local pequeno com janela pequena (8k/16k) → o prompt enche a janela e a resposta sai
truncada (
reason=length, ~1 token de saída); - janela grande (32k) → o prompt cabe, mas o processamento na GPU fica lento demais e estoura o timeout.
Ou seja: para modelo local pequeno, o gargalo não é VRAM nem janela — é o tamanho do prompt
do opencode. Conclusão operacional: usar o backend opencode com modelos cloud (janela grande,
validado) e reservar modelo local pequeno para o backend one-shot futuro (llm/mods),
que envia só o prompt — sem schemas de ferramentas nem instructions — então o modelo local
responde rápido e cabe folgado na VRAM.
Detecção de truncamento (Achado D). Tanto o caminho síncrono (Invoke-OpenCode.ps1 via
OpenCodeStreamSupport.ps1) quanto o assíncrono (Watch-OpenCodeJob.ps1) classificam a conclusão
pelo reason do último evento step_finish (Get-OpenCodeCompletionSignal /
Get-OpenCodeCompletionVerdict): só reason='stop' é sucesso; qualquer outro valor
(length, tool-calls, content_filter, unknown, max_tokens, …) ou a ausência de
step_finish/reason vira bloqueio (truncado / sem-conclusao), em vez de devolver o
preâmbulo como se fosse a resposta. O erro explícito do stream continua tendo prioridade. Esse
mapeamento de vocabulário foi validado contra o opencode em uso nesta máquina (2026-06); se uma
versão futura do opencode renomear stop (ex.: done/finished), toda chamada legítima
viraria truncado — nesse caso, revisar Get-OpenCodeCompletionVerdict e este registro. Use
-Raw (síncrono) ou o campo finishReason do result.json (assíncrono) para diagnóstico.
Retry-once opt-in (-MaxAttempts, síncrono). A truncagem por tool-calls observada em vozes
"coder" do ollama-cloud (kimi-k2.7-code, minimax-m3) é intermitente e rara — não é cota, não
é timeout, não é orçamento de passos, não é propriedade fixa do modelo; a hipótese sobrevivente é
não-determinismo de cauda (o modelo encerra logo após um tool-call sem o stop final). Como some
na repetição, Invoke-OpenCode.ps1 aceita -MaxAttempts <1-3> (default 1 = comportamento
histórico, sem re-tentativa): com 2+, re-despacha apenas veredito truncated/no-completion.
Precedência por tentativa: (1) timeout/exit≠0/erro-explícito-de-stream → terminal (lançam antes
do veredito); (2) veredito de conclusão — ok retorna, empty (stop limpo sem texto) é
terminal, só {truncated,no-completion} são re-tentáveis; (3) ao decidir re-tentar um
truncated/no-completion, checa 429 na janela da tentativa (Get-OpenCodeUsageLimitError,
$startedAt reatribuído por iteração) → se houver, terminal (não re-tentar, para não re-queimar a
cota). Sem re-tentativa pendente (-MaxAttempts 1 — o default — ou última tentativa), o veredito
reportado é o de conclusão (ex.: truncado); a checagem de 429 do passo (3) não se aplica. -TimeoutSec é por tentativa (com -MaxAttempts 2 o tempo de
parede pode dobrar); -Raw não re-tenta (devolve a 1ª execução); cada re-tentativa emite em stderr
OPENCODE_RETRY: attempt=N status=… reason=…. Síncrono-only — o assíncrono (Start-/Watch-OpenCodeJob)
sofre a mesma truncagem mas não tem retry (follow-up em 999-ideias-pendentes.md). Guard:
scripts/Test-OpenCodeRetrySelfTest.ps1 (token OK: Test-OpenCodeRetrySelfTest.ps1; fake-exe com
contador em arquivo + seam XDG_DATA_HOME para o caso 429).
LIMITE CONHECIDO — ok não garante parecer útil (sem piso de substância). O veredito ok exige
só reason='stop' + texto não-vazio — sem piso de tamanho/qualidade. Observado (2026-06-23):
minimax-m3 terminou stop com 414 chars (vs. ~16k de uma run cheia, mesmo pedido) → ok, não
re-tentado pelo -MaxAttempts (só cobre truncated/no-completion) e contado como responded no
painel. Distinto do truncamento (Achado D) e do empty (stop sem texto): aqui "termina" limpo mas
raquítico. Ver «responded exige parecer utilizável» (estados de revisor preferido, acima) e
«responded é MECÂNICO». A única mitigação atual é a reclassificação post-hoc (manual) do
orquestrador (15-revisao-por-pares.md, §Papéis parágrafo «Recibo mínimo obrigatório» — dono — /
§Recibo e livro-razão — restatement), que cobre tanto off-task quanto parecer raquítico. Critério:
descolamento do ok/responded da matéria do manuscrito, NÃO contagem de chars (ver 15). Não
é piso automático — piso/heurística segue frente aberta no 999.
Cobertura por adapter (varredura confirmatória, escopo declarado). A detecção por reason
acima é opencode-only — é fenômeno do streaming agêntico do opencode. Os demais adapters
não têm sinal de finish-reason equivalente. Uma varredura confirmatória (inspeção
estática do código-fonte dos adapters em 2026-06-20 — contrato de extração, não teste de
truncamento ao vivo) mostrou: Codex (output-last-message, arquivo dedicado), Claude Code
(stdout final), Gemini ($json.response) entregam a mensagem final canônica por campo
terminal nomeado; Copilot isola a final por last-wins de stream (último assistant.message
vence) + result.exitCode, mecanismo diferente mas com a mesma proteção prática. Critério
positivo: o adapter entrega a mensagem final canônica, não o stream/preâmbulo. Resultado:
o vazamento do Achado D (preâmbulo virar parecer) não se reproduz nos quatro não-opencode;
resta um limite conhecido residual — truncamento por limite de tokens não é detectado
fora do opencode (nenhum tem equivalente a reason=length). Esse limite (paridade de detecção de
truncamento nos adapters stdin/JSONL), o risco residual do last-wins do Copilot (se o agente
reescrever a resposta e a "última" assistant.message não for a final canônica) e um plano de
teste empírico ficam registrados em 999-ideias-pendentes.md como frente futura.
LIMITE CONHECIDO — ANTI-HANG DE STDIN HEADLESS (DOIS REGIMES)
Chamado de uma shell headless sem TTY (a ferramenta Bash/PowerShell de um agente), um CLI agêntico trava lendo o stdin herdado (um pipe aberto que nunca dá EOF): medido — o opencode pendurava por minutos. Todos os adapters dão EOF ao CLI, por um de dois regimes:
stdin-based (
Invoke-OpenCode/Start-OpenCodeJob,Invoke-Codex/Start-CodexJob,Invoke-ClaudeCode/Start-ClaudeCodeJob): entregam o prompt por stdin viaStart-Process -RedirectStandardInput <arquivo>; o fim do arquivo dá o EOF. O prompt fica fora do argv (ver a seção do limite ~32KB) e vem de-Message(inline) ou-MessagePath(arquivo, exclusivos) —-MessagePathmuda só a origem do texto, não o transporte por stdin. O opencode lê o prompt do stdin quando o argumento posicional deruné omitido (verificado no opencode em uso nesta máquina, 2026-06).argument-based (
Invoke-Gemini,Invoke-Copilot): passam o prompt como argumento e fecham o stdin no runner com$null | & ([string]$req.exe) @args($null= EOF puro, sem bytes, não'' |, que mandaria uma linha vazia antes do EOF). O runner é invocado porpwsh -File(que não lê stdin); migrar parapwsh -Commandreintroduziria o hang.Ressalva de evolução: para os argument-based, se o CLI ganhar um modo
--stdin/pipe de entrada, o stdin fechado quebraria silenciosamente; os self-tests de contrato de flags (Test-GeminiCliSupportSelfTest,Test-CopilotCliSupportSelfTest) acusam flag nova no help — revisar quando ocorrer. Para os stdin-based, a dependência inversa: se o CLI deixar de aceitar o prompt por stdin (ex.: voltar a exigir o posicional), o adapter precisaria retornar ao argv — vigiar no upgrade do opencode (a formarunsem posicional + stdin está fixada no comentário do adapter).Guard:
scripts/Test-LlmDelegateStdinHandlingSelfTest.ps1(sentinelaOK: Test-LlmDelegateStdinHandlingSelfTest.ps1) prova o EOF (fake-exe que bloqueia em stdin aberto e sai 7 ao receber EOF), trava a regressão estaticamente (stdin-based usam-RedirectStandardInpute não fecham com$null | &; argument-based fecham com$null | &) e prova o opencode stdin-based com prompt > 32KB via fake-exe injetado (-OpenCodeExe).Sondas
--version/--helpdos*CliSupport: medidas em headless (não leem stdin, não penduram), portanto não alteradas.
LIMITE CONHECIDO — StandardOutputEncoding E LINHA DE COMANDO (~32KB)
Sintoma observado (relato, não-determinístico): pela ferramenta PowerShell de um agente, "em
algumas sessões", uma chamada de adapter argument-based falhava com exit 1 e
Program '<cli>.exe' failed to run: StandardOutputEncoding is only supported when standard output is redirected. Pela ferramenta Bash (stdout = pipe) funcionava.
- Causa não confirmada. A hipótese é o host do chamador ter stdout não-redirecionado
(console-handle) e/ou o prompt grande por argv; não reproduzido de forma determinística
(medições mostraram
[Console]::IsOutputRedirected=Truenas sessões testadas, em que o erro não ocorre). Tratar como sintoma observado, não diagnóstico fechado. - Workaround para os adapters argument-based (
Invoke-Gemini,Invoke-Copilot): invocá-los pela ferramenta Bash (ou shell com stdout em pipe) e manter o prompt enxuto. - opencode resolvido por desenho.
Invoke-OpenCode/Start-OpenCodeJobdeixaram de usar o padrão& exe 1> arquivo(runner) e passaram a redireção explícita viaStart-Process -RedirectStandardOutput/-Error(que nunca dispara esse erro) + prompt por stdin — então o opencode é host-agnóstico quanto a esse sintoma, qualquer que seja a causa.
Limite de ~32KB de linha de comando do Windows (reproduzível): passar o prompt como
argumento estoura Argument list too long acima de ~32767 caracteres.
- argument-based (
Invoke-Gemini,Invoke-Copilot): o prompt vai no argv via runner → o teto ~32KB persiste. Os dois ganharam-MessagePath(lê o prompt de arquivo e elimina o(Get-Content)/"$(cat ...)"inline do chamador), mas ele não levanta o teto; um guard de tamanho fail-closed ($MaxArgvPromptChars = 30000, heurístico em chars — UTF-16 code units, margem deliberada conservadora sob o teto físico ~32767 do command line, não um limite em bytes) recusa prompts grandes comBLOCKclaro antes do estouro deArgument list too long. A migração real para stdin segue como follow-up (bloqueada por falta de assinatura para validar empiricamente) —999-ideias-pendentes.md. - stdin-based (opencode, Codex, ClaudeCode — síncronos e jobs): o prompt vai por stdin/arquivo,
não pelo argv — sem o limite. Use
-MessagePath <arquivo>(ou-Message): além de evitar o limite, dispensa"$(cat ...)"/(Get-Content)na linha de comando do chamador (sem substituição de comando = sem prompt de autorização desnecessário no harness).
LIMITE CONHECIDO — COTA/LIMITE DE USO DO PROVIDER (HTTP 429) PARECE TIMEOUT
Quando a conta do provider estoura a cota (ex.: ollama-cloud weekly usage limit, HTTP 429),
o opencode retenta em silêncio: stdout/stderr ficam vazios (confirmado até 180s) e o 429 é
gravado apenas no log próprio do opencode (~/.local/share/opencode/log/<ts>.log; respeita
XDG_DATA_HOME). Sem tratamento, a chamada só estoura por -TimeoutSec e parece timeout técnico.
Invoke-OpenCode.ps1diagnostica isso: no branch de timeout,Get-OpenCodeUsageLimitError(emOpenCodeStreamSupport.ps1, dot-source;-LogDirpara fixture) varre o log da janela do processo por"statusCode":429+ a mensagem de limite e lança um erro claro ("limite de uso do provider (HTTP 429)… aguardar o reset do ciclo"), em vez de "excedeu Xs". Self-testTest-OpenCodeUsageLimitDetectionSelfTest.ps1(tokenOPENCODE_USAGE_LIMIT_DETECTION_SELFTEST_OK).- Não adianta redisparar nem aumentar o timeout — só reseta no ciclo de uso (semanal no ollama-cloud) ou com upgrade/extra usage. Outras famílias (Codex/Claude Code nativo/nvidia) não são afetadas pela cota do ollama-cloud.
- Follow-up: estender a detecção aos jobs opencode (
Start-/Watch-OpenCodeJob) e aos demais backends —999-ideias-pendentes.md.
LIMITE CONHECIDO — OPENCODE: AGENTE DEFAULT AUTO-APROVA FERRAMENTAS LOCAIS EM HEADLESS
Observação empírica (opencode 2026-06; não-contratual): em opencode run headless (sem TTY), as
permissões de ferramenta do agente default build — e do --agent plan — são auto-aprovadas:
o modelo executou bash (e a rotina pré-push real) sem gate interativo. Consequência: ao despachar
para um modelo externo via Invoke-OpenCode.ps1 com o agente default, o painel concede a esse modelo
execução de comandos arbitrários na máquina durante a tarefa.
- Dois eixos de risco: (i) execução arbitrária local — vale para qualquer modelo (inclusive local), porque o opencode auto-aprova as tools em headless; (ii) exfiltração — agravante específico do modelo externo.
- O gate de confidencialidade não cobre este eixo.
Resolve-LlmDelegateAuthorization.ps1governa se o dado sai (destino/sensibilidade), não a capacidade do modelo de executar/ler localmente — eixos distintos. Caso central deste repositório: payloadpubliccai emallowautomático (validação de plano/design na raiz das skills é o caso nobre da diversidade externa), então o risco de execução local não passa por nó humano. Vale também paraaskautorizado (consentir o envio também concede execução). - Mecanismo de contenção é DIFERENTE do Codex/Claude/Gemini (que usam
--approval-mode plan/PermissionMode=plan): no opencode a contenção é por configpermissionem arquivo de agente custom (permission: bash: deny/edit: deny).-Agent <nome>por si só não mitiga — só mitiga se o agente custom negar as ferramentas. Limite residual: mesmo negandobash/edit, a toolread(default) lê qualquer arquivo (config com baseURL/chaves,.env) — eixo de leitura ainda aberto (e o adapter opencode não tem-Cdpara conter o cwd). Ver999-ideias-pendentes.md(frente "agente reviewer sem execução/escrita"). - Regra operacional (revisor opencode = read-only obrigatório). Ao usar opencode como revisor (revisão por pares / pré-push reforçada), nunca despachar com o agente default
build/plan: o revisor não pode escrever. Despachar com-Agent <custom>cujo arquivo declarepermission: edit: deny(ebash: denyquando a revisão não exigir execução); enquanto esse agente não estiver provisionado (ver999-ideias-pendentes.md), preferir um revisor read-only de outra família (Codex em sandboxread-only; Claude Code com tools restritos) a conceder escrita ao opencode. Incidente concreto (2026-06-24, pré-push reforçada): um revisor opencode (kimi-k2.7-code, agente default) editou um.mddo repo (corrigiu um typo) em vez de só reportar — o eixoeditse materializou; o orquestrador inspecionou o diff antes de adotar, mas a edição pelo revisor não devia ser possível.
LIMITE CONHECIDO — CODEX É AGÊNTICO (HERDA O AGENTS.md, PODE EXECUTAR)
O codex exec também é agêntico: carrega o AGENTS.md/config do Codex como instruções e,
mesmo com sandbox read-only (fixo nos adapters), pode ler o filesystem do workspace e
executar comandos read-only para cumprir as instruções herdadas (medido: ~50k tokens de input
e execução espontânea de Get-Date por causa de uma regra do AGENTS.md global). Consequências:
- Não é um backend one-shot: o prompt por chamada é grande e o agente pode agir no workspace.
Para segunda opinião limpa, confinar com
-Cd <dir>e preferir um workspace sem dados sensíveis. - O
read-onlynão contorna o gate: o Codex envia para a OpenAI (externo). Em pasta paralela de KB, payload sensível continua exigindo autorização — o adapter agêntico não tem proteção nativa de leitura ali (mesmo alerta do opencode em## CONTEXTOS DE USO). - Reserva-se ainda o backend one-shot futuro (
llm/mods) para o caso que precisa enviar só o prompt, sem agente nem varredura de filesystem.
LIMITE CONHECIDO — CLAUDE CODE É AGÊNTICO E EXTERNO
O claude -p também é agêntico: pode carregar instruções/configurações do Claude Code,
ler o workspace e executar ferramentas conforme permissões. Além disso, Opus 4.8 envia o
payload para Anthropic (anthropic/claude-opus-4-8) e, portanto, é externo. Consequências:
- O gate de confidencialidade continua obrigatório: payload
kb-sensitivepara Claude Code externo sem política durável devolveask;allowexige anunciartargetModelKey. - Para consulta curta restrita, usar os defaults do adapter:
-PermissionMode plan,-Tools Read,Glob,Grep, persistência de sessão desabilitada e-Cdapontando ao menor diretório necessário.-MaxTurnssó entra quando a CLI local suportar--max-turns. - Para revisor pré-push, a rotina pode precisar de
gite scripts locais; não reaproveitar cegamente o perfil restrito de consulta curta. Definir explicitamente ferramentas/permissões suficientes para leitura e comandos de validação, sem usarbypassPermissions. - Os adapters
Invoke-ClaudeCode.ps1eStart-ClaudeCodeJob.ps1bloqueiamPermissionMode=bypassPermissions; esse modo não faz parte da delegação XPZ.
LIMITE CONHECIDO — COPILOT CLI E GEMINI CLI TAMBÉM SÃO AGÊNTICOS EXTERNOS
O copilot -p e o gemini -p são CLIs agênticas, não backends one-shot puros. Mesmo em
consulta curta, podem carregar contexto próprio e são serviços externos: Copilot casa
github-copilot/*; Gemini casa google/*. Consequências:
- O gate de confidencialidade continua obrigatório para payload
kb-sensitive; sem política durável, ambos devolvemask. - Para Copilot, o adapter usa
--no-custom-instructions,--disable-builtin-mcpse--available-tools=; o teste local comprovou resposta comtools_updatedsem ferramentas executadas efilesModified=[]. - Para Gemini, o adapter usa
--approval-mode plan; os testes manuais em PowerShell 7 comprovaramtools.totalCalls=0efiles.totalLinesAdded/Removed=0. - Nenhum dos dois substitui o backend one-shot futuro (
llm/mods/equivalente) para o caso em que é essencial enviar só o prompt sem camada agêntica.
BACKENDS
Ativos: opencode (#1), Codex (#2), Claude Code (#3), GitHub Copilot CLI (#4)
e Gemini CLI (#5). O Codex exerceu o ponto de
extensão do núcleo: o gate ganhou -Backend e passou a casar a política pelo canonicalModel
do resolvedor (chave de destino), sem renomear LlmDelegate nem tocar o resolvedor do
opencode. O Claude Code reaproveita o mesmo eixo: adapter próprio, resolvedor próprio e chave
de destino anthropic/*. Copilot e Gemini seguem a mesma regra, com chave de destino
github-copilot/* e google/*, respectivamente.
Futuros (ex.: CLIs one-shot tipo llm/mods, mais seguras para segunda opinião pois não varrem
o filesystem) entram do mesmo jeito: um adapter de invocação + um resolvedor de localidade
próprio, plugados no mesmo gate por -Backend.
RELAÇÃO COM OUTRAS SKILLS
xpz-kb-parallel-setup: oferta, no setup da pasta paralela, definir a política de delegação (llm-delegation-policy.json; nome legadoopencode-delegation-policy.jsonainda aceito), com opção de adiar — adiar mantém o comportamentoask, nunca abre brecha.xpz-skills-setup: registra esta skill nas ferramentas de agente instaladas.