Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"name": "flux",
"source": "./plugins/flux",
"description": "Ciclo de trabalho agêntico para qualquer repo Git: probe, refine, issue, build, peek, review, iterate, land e reply, o chain que os encadeia, mais o map e o equip, que preparam a máquina e o repo. Global e context-agnóstico, com o que é específico do seu time vindo de um manifesto, nunca hardcoded.",
"version": "1.45.2"
"version": "1.46.0"
}
]
}
2 changes: 1 addition & 1 deletion .cursor-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"name": "flux",
"source": "./plugins/flux",
"description": "Ciclo de trabalho agêntico para qualquer repo Git: probe, refine, issue, build, peek, review, iterate, land e reply, o chain que os encadeia, mais o map e o equip, que preparam a máquina e o repo. Global e context-agnóstico, com o que é específico do seu time vindo de um manifesto, nunca hardcoded.",
"version": "1.45.2"
"version": "1.46.0"
}
]
}
2 changes: 1 addition & 1 deletion plugins/flux/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "flux",
"description": "Ciclo de trabalho agêntico para qualquer repo Git: probe, refine, issue, build, peek, review, iterate, land e reply, o chain que os encadeia, mais o map e o equip, que preparam a máquina e o repo. Global e context-agnóstico, com o que é específico do seu time vindo de um manifesto, nunca hardcoded.",
"version": "1.45.2",
"version": "1.46.0",
"author": {
"name": "Gabriel Gripp",
"email": "550632+grippado@users.noreply.github.com"
Expand Down
2 changes: 1 addition & 1 deletion plugins/flux/.codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "flux",
"version": "1.45.2",
"version": "1.46.0",
"description": "A complete, harness-neutral work cycle for Git repositories: probe, refine, issue, build, peek, review, iterate, land, and reply, chain to link them, plus map and equip, which prepare the machine and the repository.",
"author": {
"name": "Gabriel Gripp",
Expand Down
2 changes: 1 addition & 1 deletion plugins/flux/.cursor-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "flux",
"description": "Ciclo de trabalho agêntico para qualquer repo Git: probe, refine, issue, build, peek, review, iterate, land e reply, o chain que os encadeia, mais o map e o equip, que preparam a máquina e o repo. Global e context-agnóstico, com o que é específico do seu time vindo de um manifesto, nunca hardcoded.",
"version": "1.45.2",
"version": "1.46.0",
"author": {
"name": "Gabriel Gripp",
"email": "550632+grippado@users.noreply.github.com"
Expand Down
42 changes: 36 additions & 6 deletions plugins/flux/shared/codex-compat.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,42 @@ O resto do protocolo não muda e não é repetido aqui: vale

### Perguntas ao usuário

Este adaptador não define uma ferramenta de pergunta estruturada ao usuário, nem um contrato
verificado de entrega visual e retorno da escolha à mesma sessão. Portanto, no Codex o round-trip não
está comprovado: para todo GATE, a main apresenta o fallback numerado de
[`hitl.md`](hitl.md), com as opções e descrições completas aplicáveis, e espera uma escolha explícita
no chat antes de agir. A disponibilidade de uma ferramenta ou a aceitação técnica de uma solicitação
não muda esse caminho. Não delegar o gate a um subagente.
No Codex, a pergunta estruturada é a ferramenta nativa `request_user_input`. Ela só existe quando a
feature `default_mode_request_user_input` está ligada (`under development` e desligada por padrão no
Codex; ligar é configuração da máquina, não do flux).

Quando `request_user_input` estiver disponível na sessão, a main a usa para todo GATE, com uma
question single-select por gate, e espera a escolha retornar à mesma sessão antes de agir. O gate
continua na main: não delegar a um subagente. O round-trip está comprovado para o Codex 0.161.0 ou
superior com a feature ligada; uma resposta com escolha na própria sessão é a confirmação de que ele
funciona ali, e não se exige prova adicional antes da primeira chamada.

Round-trip comprovado em 2026-10-08, no Codex 0.161.0 com
`-c features.default_mode_request_user_input=true`: a ferramenta desenhou o menu com seta e descrição
por opção, e a escolha voltou à mesma sessão ("Questions 1/1 answered"). Esta comprovação vale para
essa versão com a feature ligada e se estende a versões posteriores até um caso em contrário. Não foi apurado o comportamento em `codex exec` headless nem com menus de 5 ou mais opções.

Cai no fallback numerado de [`hitl.md`](hitl.md), com as opções e descrições completas e espera de
escolha explícita no chat, quando qualquer destas condições valer:

- a ferramenta não está disponível na sessão (feature desligada ou versão anterior à 0.161.0);
- a chamada é aceita sem devolver escolha nenhuma (por exemplo, `{"accepted":true}` da variante
assíncrona): isso não comprova round-trip, e o gate cai no numerado na hora;
- a pergunta estruturada voltou vazia (`{"answers":{}}`) três vezes seguidas para o mesmo gate;
- o menu do gate não cabe na ferramenta ou a chamada é recusada: nunca truncar opção em silêncio;
- a sessão é headless (o bloco de preflight traz `gate_signal:`): vale o sinal `flux-gate/1` de
`hitl.md`, "Execução headless".

**Resposta vazia não é recusa.** A chamada espera a pessoa por um limite fixo (cerca de 120 segundos
no Codex 0.161.0, sem chave de configuração conhecida; acompanhamento em
[openai/codex#37472](https://github.com/openai/codex/issues/37472)) e devolve `{"answers":{}}` quando ele expira. Isso
só diz que a pessoa ainda não respondeu: repetir a mesma pergunta estruturada, sem alterar texto nem
opções, até três vezes, e só então cair no numerado. Nenhuma ação acontece sem escolha explícita, em
nenhuma das tentativas.

Quando cair no numerado porque a pergunta estruturada está ausente, foi aceita sem escolha ou voltou
vazia nas três tentativas, declarar `pergunta estruturada ausente` em `degradacoes:`
(`${FLUX_ROOT}/shared/preflight.md`, Passo 5).

### Adaptador de instruções de agente

Expand Down
16 changes: 12 additions & 4 deletions plugins/flux/shared/hitl.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,12 @@ quando o round-trip estiver comprovado na sessão atual: a pergunta e as opçõe
escolha dela retorna ao mesmo contexto principal. A mera disponibilidade de uma ferramenta, a
aceitação técnica da chamada ou uma resposta sem escolha não comprovam esse round-trip.

- Use `AskUserQuestion` só quando esse round-trip estiver comprovado.
- Use `AskUserQuestion` (Claude Code, Cursor) ou `request_user_input` (Codex) só quando esse
round-trip estiver comprovado. A comprovação e as condições de queda de cada harness vivem em
`${FLUX_ROOT}/shared/codex-compat.md`, "Perguntas ao usuário".
- O Codex acrescenta sozinho a opção "None of the above" com campo de notas ao menu de
`request_user_input`. Não declará-la no menu: a saída inócua continua sendo a última opção
declarada.
- Sem round-trip comprovado, use o fallback numerado abaixo, mesmo que a ferramenta esteja
disponível ou tenha aceitado a solicitação.

Expand All @@ -66,7 +71,7 @@ aceitação técnica da chamada ou uma resposta sem escolha não comprovam esse

## Fallback quando o round-trip não está comprovado

`AskUserQuestion` é um tool do harness, não uma garantia da linguagem nem da interface. Quando a
`AskUserQuestion` e `request_user_input` são tools do harness, não uma garantia da linguagem nem da interface. Quando a
sessão não oferece o mecanismo ou o round-trip não está comprovado, o gate **não desaparece** — muda
de forma:

Expand All @@ -77,8 +82,11 @@ de forma:
a recomendada por iniciativa própria, não interpretar silêncio, aceitação técnica da chamada ou
retorno sem escolha como consentimento. Numa execução headless não há quem responda: antes de
encerrar, gravar o sinal da seção "Execução headless" abaixo.
3. Declarar a degradação no banner de perfil, como qualquer `soft` ausente
(`${FLUX_ROOT}/shared/preflight.md`, Passo 5).
3. Declarar no banner a degradação correspondente ao motivo do fallback, conforme o contrato do
harness e a tabela de `${FLUX_ROOT}/shared/preflight.md`, Passo 5. No Codex, ferramenta estruturada
ausente, aceita sem escolha ou vazia nas três tentativas gera `pergunta estruturada ausente`; menu que não cabe
na ferramenta e sessão headless seguem o fallback numerado sem esse token, pois esses casos são
tratados como caminhos esperados pelo adaptador (`${FLUX_ROOT}/shared/codex-compat.md`, "Perguntas ao usuário").

> **A degradação é de forma, nunca de rigor.** Um gate que vira "escolhi a recomendada porque não
> tinha como perguntar" é pior do que não ter gate nenhum: produz uma ação não autorizada com
Expand Down
1 change: 1 addition & 0 deletions plugins/flux/shared/preflight.md
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ que o banner precisa ser.
| `transporte mcp` | um canal com dois caminhos (`${FLUX_ROOT}/shared/api-first.md`) foi servido pelo MCP em vez da API — sai com o canal e o motivo em grafia fixa: `transporte mcp (linear: sem token \| token nao autentica \| alvo nao enxergado \| canario falhou \| leitura falhou \| opt-out)`. Caminho por API não gera token: é o default, e declarar o default é ruído | o elo que aplicou o contrato (`issue`, `build`, `land`) |
| `versao ilegivel` | `FLUX_VERSION = unknown`: nenhum dos três manifests (`plugin.json`) foi lido com sucesso ou o campo `version` estava ausente — a linha `carimbo:` exibe `unknown` | o Passo 1a-harness |
| `chain interrompido` | um elo do chain parou por falha, ou deixou decisão sem resposta, e os elos seguintes **não rodaram** — sai com o elo e o motivo, e acompanha o bloco de estado do chain. Usuário que escolhe a saída inócua de um gate **não** gera este token: é decisão, não interrupção | o `flux:chain` (`${FLUX_ROOT}/shared/chain.md`, "Falha no meio") |
| `pergunta estruturada ausente` | o harness é Codex, `request_user_input` não está disponível na sessão foi aceita sem escolha ou voltou vazia nas três tentativas, e o GATE caiu no menu numerado de `${FLUX_ROOT}/shared/hitl.md`; sai sem motivo adicional. Menu que não coube na ferramenta e sessão headless não geram token: o numerado ali é o contrato, não ausência | o elo que apresenta o gate (`${FLUX_ROOT}/shared/codex-compat.md`, "Perguntas ao usuário") |
| `gate signal indisponivel` | o bloco `PREFLIGHT RESOLVIDO` da invocação traz `gate_signal: indisponivel (<motivo>)`: a CLI não tem como receber o sinal de gate pendente nesta execução; sai com o motivo que o bloco trouxe, sem reescrever. Campo ausente **não** gera token | ainda não implementado por nenhum elo: quem passar a **ler** o bloco da invocação e puder parar num gate (`${FLUX_ROOT}/shared/hitl.md`, "Execução headless") |
| `gate signal nao gravado` | o bloco traz `gate_signal: <caminho>` e a gravação do sinal falhou (diretório ausente, sem permissão, rename recusado): sai com o motivo literal do erro, e o gate ficou pendente sem sinal. Não bloqueia o elo | ainda não implementado por nenhum elo: o mesmo que lê `gate_signal` (`${FLUX_ROOT}/shared/hitl.md`, "Execução headless") |

Expand Down