flux

agent
Security Audit
Fail
Health Warn
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 8 GitHub stars
Code Fail
  • rm -rf — Recursive force deletion command in benchmark/run.sh
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

The full agentic work cycle, idea to merge, without switching tools. Plugin for Claude Code, Cursor and Codex.

README.md
   ███████╗██╗     ██╗   ██╗██╗  ██╗
   ██╔════╝██║     ██║   ██║╚██╗██╔╝ ██╗
   █████╗  ██║     ██║   ██║ ╚███╔╝  ╚═╝
   ██╔══╝  ██║     ██║   ██║ ██╔██╗  ██╗
   ██║     ███████╗╚██████╔╝██╔╝ ██╗ ╚═╝
   ╚═╝     ╚══════╝ ╚═════╝ ╚═╝  ╚═╝

   da ideia ao merge, sem trocar de ferramenta

site release license claude code cursor codex cli

Família de comandos globais e context-agnósticos que cobre o ciclo inteiro de trabalho num repo: da telemetria de produção ao código, do código ao review, do review ao merge, do merge à comunicação.

grippado.github.io/flux: a landing com o ciclo, a instalação por harness e as versões publicadas. O selo de release acima aponta sempre para a última, sem ninguém precisar lembrar de atualizar este arquivo. A landing, porém, só muda quando a release é aprovada: o merge de uma versão nova dispara o workflow, mas ele espera um clique (ver Publicar uma versão).

Instalação

O Flux é um corpo de workflows com adaptadores por harness. O mesmo plugins/flux/ (as skills, os agents, os shared) serve Claude Code, Cursor e Codex: não há fork de comportamento nem arquivo duplicado.

Claude Code

/plugin marketplace add grippado/flux
/plugin install flux@flux

Cursor

git clone https://github.com/grippado/flux ~/code/flux
~/code/flux/scripts/install-cursor.sh
# encerrar o Cursor por completo e abrir de novo

Os verbos ficam como /flux-peek, /flux-review, /flux-iterate. Confira em Settings → Customize → Plugins.

O script existe por dois motivos que não dá para resolver no README:

O Cursor não segue symlink em ~/.cursor/plugins/local/. Um symlink registra o plugin e não carrega nada, sem erro em lugar nenhum. Tem que ser diretório real, então o script copia.

O Cursor não prefixa skill de plugin. O nome invocável sai do campo name do frontmatter, e sem namespace: name: peek viraria /peek, no mesmo espaço onde o próprio Cursor já tem uma skill nativa chamada review. Prefixar na fonte não serve, porque o Claude Code usa o mesmo campo e viraria /flux:flux-peek. Então o prefixo é aplicado na cópia instalada, pelo script. O repo mantém um nome só por verbo.

Não há hot-reload: a cada git pull, rode o script de novo e encerre o Cursor por completo antes de reabrir. Fechar a janela normalmente deixa o app rodando, e ele volta com a versão antiga em memória — o sintoma é confuso, porque o elo funciona, só que com o comportamento da versão anterior.

Em plano Teams/Enterprise dá para importar o repo em Dashboard → Plugins e distribuir pelo marketplace do time, com auto-refresh.

Codex

O Flux já pode ser instalado do marketplace do próprio repositório:

codex plugin marketplace add grippado/flux
codex plugin add flux@flux

Abra uma sessão nova depois da instalação. O repositório fornece o catálogo em
.agents/plugins/marketplace.json, que aponta para o pacote nativo
plugins/flux/.codex-plugin/plugin.json. O catálogo público universal ainda depende da submissão e
aprovação da OpenAI; até lá, este marketplace Git é o caminho instalável e compartilhável.

A forma de invocar uma skill é a que o Codex registrar; use @Flux ou o nome exibido pela sessão,
nunca presuma /flux:.

O adaptador Codex usa a delegação nativa de subagentes para o fan-out. Como o Codex não registra
os nomes customizados de subagent_type de Claude/Cursor, ele resolve arquivos de instrução
legíveis e entrega o path ao subagente nativo; o banner e a cobertura mostram a fonte que de fato
rodou. MCP, vault, Linear, Slack e specialists são capacidades opcionais: quando ausentes, o
preflight declara a degradação e o Flux continua no perfil genérico.

CLI

A CLI resolve o preflight fora de qualquer sessão de IA e já roda o Claude Code com o prompt
armado, eliminando a etapa manual de copiar e colar. Em vez de abrir o Claude e digitar
/flux:review meu-repo, você roda flux review meu-repo no terminal — por padrão na aba
atual
(equivalente ao antigo --here, agora o comportamento default).

flux review meu-repo                  # roda na aba atual, prompt já armado
flux review 31 --repo flux --dry      # só monta e mostra o comando, não executa
flux build meu-repo --new             # abre aba nova (iTerm2/Terminal.app) em vez de rodar aqui

Sem nenhum argumento, num terminal de verdade, a CLI entra em modo interativo: um menu
navegável por seta (↑↓ ou j/k, número ou Enter, Esc cancela) pergunta o comando — com uma
descrição curta de cada um —, depois o alvo (PR/URL/ticket/path, opcional), o repo (opcional) e
se quer rodar numa máquina remota.

$ flux
flux — modo interativo (sem argumentos). Qual comando?
(setas ou j/k pra navegar, número ou Enter pra confirmar, Esc cancela)

  review   revisão formal de PR/doc (specialists + reviewer)
❯ build    implementa um ticket, entrega PR draft
  peek     relance rápido e read-only de PR/diff/doc
  ...

Prévia do banner antes de disparar. Com terminal interativo (e sem --dry), antes de abrir o
Claude Code a CLI mostra o banner completo que vai ser enviado e um menu de seta com três opções:
enviar como está (Enter no primeiro item), anexar um comentário extra ao banner, ou cancelar.
--yes/-y pula essa prévia — útil pra quem já confia no fluxo e não quer o passo extra toda vez.

Rodar numa outra máquina, via SSH. --remote <alias> reencaminha o comando inteiro pra um
alias já configurado no seu ~/.ssh/config — herda o terminal atual do outro lado, como se você
tivesse aberto uma sessão SSH e rodado o flux de lá. Sem valor (--remote sozinho), a CLI lista
os Host alcançáveis agora e pergunta qual usar (mesmo menu de seta); um comentário
# flux:ignore na linha acima de um Host tira aquele alias da lista — útil pra servidor de
produção que só está no ~/.ssh/config por conveniência, não pra rodar sessões do flux.

flux review 31 --repo flux --remote worzix   # dispara direto no alias "worzix"
flux review 31 --repo flux --remote          # pergunta qual máquina alcançável usar

Limitação declarada: a abertura automática de aba (--new) suporta só o Claude Code, e só
funciona no iTerm2 e no Terminal.app (macOS); em qualquer outro emulador, ou fora do macOS, a CLI
imprime o comando no stdout e avisa no stderr, para você colar e rodar na mão.

Permissões: por default a sessão abre com claude --dangerously-skip-permissions — a CLI existe
para despachar trabalho, e uma aba que para no primeiro prompt de permissão não despacha nada. Quem
preferir a sessão com os gates de permissão do harness passa --safe. Para usar um wrapper próprio no
lugar do claude (um alias de conta, um launcher com sync), exporte FLUX_CLAUDE_CMD com o comando
completo: ele é usado verbatim e as flags passam a ser responsabilidade dele.

Instalação

cd cli
bun run setup     # builda, re-assina (macOS) e instala em ~/.local/bin/flux

bun run setup é o atalho de dev: builda o binário, re-assina no macOS (necessário em máquinas com
MDM/EndpointSecurity — sem isso o primeiro exec depois de cada build pode morrer com "killed" e um
load code signature error no log do sistema, sem indicar nada de errado no binário em si), e
copia pra ~/.local/bin/flux. Preferindo fazer na mão, ou instalar em outro lugar:

cd cli
bun run build                  # gera o binário ./flux
codesign --force --sign - flux # macOS com MDM/EndpointSecurity; opcional nos demais casos
mv flux ~/.local/bin/flux      # ou outro diretório no seu PATH

Permissão de automação no primeiro uso do --new (macOS): ao rodar o primeiro flux <verbo> --new, o macOS pode exibir um diálogo pedindo permissão para o terminal controlar o iTerm2 ou o
Terminal.app via AppleScript. Aceite o diálogo; a permissão fica salva em Preferências do Sistema →
Privacidade e Segurança → Automação. Sem --new (o padrão), essa permissão nunca é pedida.

FLUX_HOME: se você não instalou o flux como plugin de nenhum harness, defina FLUX_HOME
apontando para o diretório plugins/flux do seu checkout. A CLI usa essa variável como fonte
explícita do FLUX_ROOT antes de tentar a heurística.

export FLUX_HOME=~/code/flux/plugins/flux

Flags

Flag Efeito
--repo <slug> repo alvo, quando não dá pra inferir do alvo ou do cwd
--dry só imprime o comando/prompt montado, sem executar nada nem mostrar a prévia do banner
--safe roda com os gates de permissão do harness, em vez de --dangerously-skip-permissions
--new abre aba nova (iTerm2/Terminal.app) em vez de rodar na aba atual (o padrão)
--remote [alias] roda na máquina do alias (~/.ssh/config); sem valor, pergunta interativamente
--yes, -y pula a prévia do banner antes de disparar
--record só em flux review <PR>, no modo here: grava um run local em ~/.flux/runs/<run_id>/ (run.md, 01-review.md, outcome.md), privado e opt-in. Recusa --new e --remote. Com --record, um preflight que aborta (exit 3) impede o disparo, o que sem a flag não acontece. Ver run.md e a PRIVACY.md

Exemplos

flux resolve . --json                 # inspeciona o contexto resolvido no cwd
flux review 31 --repo flux --dry      # monta o prompt sem executar nada
flux review meu-repo                  # roda na aba atual, /flux:review meu-repo pronto
flux build meu-repo --new             # mesma coisa, mas abrindo aba nova
flux review 31 --repo flux --remote   # escolhe interativamente uma máquina acessível via SSH
flux                                  # modo interativo: pergunta comando, alvo, repo e remoto

Depois de instalar, nos três

Depois de instalar, os verbos ficam disponíveis em qualquer repo Git. No Claude Code, a forma
é /flux:peek; no Cursor, /flux-peek; no Codex, use o nome que o Plugin Directory registrar.

Uma ressalva honesta sobre o Codex: o flux:land e o flux:chain despacham um irmão, e para isso
precisam resolver o prefixo de invocação da família — coisa que o Codex ainda não expõe de forma
verificável. O land aborta a fase de despacho; o chain valida a gramática e imprime o plano, mas
não executa os elos. Nenhum dos dois degrada para uma iteração fora do contrato. map e refine
também perdem uma capacidade lá, e o iterate perde o watch: faz a passada, declara a degradação e
o usuário reinvoca o verbo para a próxima rodada. Detalhe em
shared/codex-compat.md.

Requisitos reais: git (duro — sem ele o preflight aborta) e gh autenticado (mole, mas é o que separa "roda em PR" de "roda só na working tree"). O jq é mole e só interessa ao watch do flux:iterate: sem ele o watch troca o gate mecânico pelo modo agendado, com a perda declarada. Nada além disso. Sem manifesto, sem vault e sem specialists, a família roda no perfil genérico e o banner do preflight declara o nível degradado em vez de fingir que está completo.

Dois elos dependem de MCP e degradam sem ele: o flux:reply precisa de um canal de Slack, e o modo doc do flux:review/flux:peek precisa de um canal de documentos. Qual servidor atende cada canal vem do campo mcp do manifesto; sem o campo, o elo procura a capacidade na sessão. Nenhum id de MCP é hardcoded na família — ele depende de como cada máquina instalou o servidor.

Para somar specialists, persistência no vault e integrações do seu time, declare um manifesto de contexto. Exemplos prontos em examples/.

O que é

flux: é um ciclo, não um conjunto de utilitários. Cada comando é um elo com fronteira nítida, e o elo seguinte assume onde o anterior parou. Você nunca sai da família para completar uma entrega.

Dois princípios sustentam isso:

  1. Os comandos são globais e não sabem nada do seu time. Eles vivem na raiz da instalação (${FLUX_ROOT}/skills/) e funcionam em qualquer repo Git, em qualquer harness. O que é específico de um time (quais reviewers, qual vault, quais repos) vem de um manifesto de contexto — flux-context.json —, nunca hardcoded no comando.
  2. Cada elo delega o trabalho especializado. Review vai para agents reviewers; execução vai para o motor nativo do repo; prospecção de codebase vai para specialists. Os comandos orquestram, não reimplementam.

O ciclo

  ┌ fora do ciclo, uma vez por máquina / por repo ──────────────────┐
  │  ┌───────────────────────┐      ┌───────────────────────┐       │
  │  │   flux:map            │─────▶│   flux:equip          │       │
  │  │   levanta a instalação│      │   L0 motor · L2 suite │       │
  │  │   e diz o que falta   │      │   expõe a L3          │       │
  │  └───────────────────────┘      └───────────────────────┘       │
  └──────────────────────────┬──────────────────────────────────────┘
                             ┆ sugeridos antes, exigidos por nada
                             ▼
        ideia / thread / bug relatado / link de telemetria
                    │
        ┌───────────┼───────────┬───────────┐
        │(opcional) │(opcional) │ (direto)  │
        ▼           ▼           │           │
┌──────────────┐ ┌───────────────────────┐  │
│ flux:probe   │ │   flux:refine         │  │  probe: o que a telemetria PROVA
│ dossiê de    │▶│   mede o escopo antes │  │  refine: fast SDD numa rodada
│ produção     │ │                       │  │  escopo grande → recusa e corta
└──────┬───────┘ └───────────┬───────────┘  │
       └─────────────┬───────┴──────────────┘
                     ▼
        ┌───────────────────────┐
        │   flux:issue          │  fonte livre → issue embasada em código real
        └───────────┬───────────┘
                    ▼
        ┌───────────────────────┐
        │   flux:build          │  issue → código + PR draft
        └───────────┬───────────┘  (despacha ao motor nativo do repo)
                    ▼
        ┌───────────────────────┐        ┌───────────────────────┐
        │   flux:peek           │        │   flux:review         │
        │   relance read-only   │◀──ou──▶│   review formal       │
        │   não posta, não grava│        │   persiste no vault   │
        └───────────┬───────────┘        └───────────┬───────────┘
                    └──────────┬─────────────────────┘
                               ▼
                   ┌───────────────────────┐
                   │   flux:iterate        │  threads → correções → push → CI verde
                   └───────────┬───────────┘  ↻ fica vivo até a PR assentar
                               ▼
                   ┌───────────────────────┐
                   │   flux:land           │  N PRs → toposort → merge-ready → go/no-go
                   └───────────┬───────────┘  (não mergeia: humano decide)
                               ▼
                   ┌───────────────────────┐
                   │   flux:reply          │  comunica, embasado no que de fato mudou
                   └───────────────────────┘

Nenhum elo é obrigatório e nenhum chama o próximo sozinho. Cada um termina apontando o elo seguinte e devolvendo o volante para você.

O flux:refine é o ramo opcional da entrada, e por isso
aparece pontilhado: o ciclo funciona inteiro sem ele. Ele existe para o pedido que chegou como ideia
crua, sem ninguém ter escrito por que aquilo importa, onde encosta no código e por onde começar. Numa
rodada ele produz PRD, TRD e plano de slices no mesmo board que o flux:issue consome depois,
então a prospecção acontece uma vez só. E ele mede o escopo antes de trabalhar: pedido grande
demais para uma rodada é recusado com o corte proposto, em vez de virar um refinamento raso com
aparência de completo. O contrato do gate é o scope-gate.md.

Quando o gatilho "decisão de produto em aberto sem dono" do
scope-gate.md é o único sinal duro do 🔴, sem outro sinal duro
concorrente e com no máximo 1 sinal mole, o Caminho grill entra no lugar da recusa seca: busca
evidência real das alternativas que o pedido sugere (precedente no código, ferramenta equivalente já
existente, doc relacionado) e abre um gate para você decidir; sem alternativa sugerida, ele nomeia o
gap e segue para o Caminho vermelho normal, sem gate. A decisão fica registrada na Timeline do board
(ou só no chat, em perfil sem VAULT_ROOT), e o escopo é medido de novo a partir dali. Roda
automaticamente sempre que o gatilho bate, exceto sob --dry, que para no veredito e só nomeia o
gap; --grill só documenta a intenção no comando.

O flux:probe é o outro ramo opcional da entrada, e o único
que começa antes de existir um pedido. Bug de produção não chega refinável: chega como um link, um
contador e uma mensagem de erro que descreve o último passo da falha, quase nunca o primeiro. O probe
agrega os eventos, mede, testa a explicação corrente contra a física dos números e cruza o resultado
com o código que emite aquele sinal.

Ele lê duas famílias de fonte, e elas cobrem lados diferentes da mesma falha. Um rastreador de
erros entrega o alvo já agrupado, e costuma ver o cliente; uma plataforma de observabilidade não
agrupa nada (o alvo é uma pergunta, e o agrupamento se constrói na hora), e vê o servidor. Entrando as
duas na mesma execução, o elo responde a pergunta que nenhuma delas responde sozinha: o servidor viu
o que o cliente relatou?
Ausência do lado do servidor fecha meia investigação de uma vez. Ele escreve no mesmo board do refine e do issue, então o
que ele apurou não é reapurado depois. Quando o dossiê mostra que o pedido é grande, o handoff é para
o refine; quando ele já nomeia as correções, é direto para o issue.

Acima do ciclo, e fora dele, moram dois verbos que não tratam de uma entrega:

  • flux:map — o verbo de sanidade. Levanta a instalação inteira nesta máquina (raízes de agents, manifestos, repos, as três lentes de cada um, colisões de nome), grava o índice que os demais elos consomem, e relata o que está torto com a remediação de cada caso. Executando de novo, mostra o delta: agents novos, repos novos, suites que quebraram. E não para no diagnóstico: item a item, ele despacha o flux:equip para consertar o que você aceitar, vários repos em paralelo, reconciliando o índice no fim. É o candidato natural a primeiro comando numa máquina nova.
  • flux:equip — o verbo de preparo. Equipa um repo com o motor de execução e a suite de specialists que os elos consomem, e expõe a L3 do repo quando ela existe e não está alcançável. Entra quando falta alguma dessas camadas, e sai.

A divisão entre os dois é limpa: map levanta, propõe e despacha; equip é quem escreve o reparo. Nenhum conserto acontece fora do verbo que é dono do gate daquela escrita, e recusar tudo no gate deixa o map sendo o que ele era, um levantamento — a propriedade que faz dele um comando que se roda sem medo.

Nenhum dos dois é pré-requisito de nada. Sem eles, todo elo cai na varredura direta e declara a degradação no banner — o comportamento que a família sempre teve. Eles melhoram o resultado; não o habilitam. Uma família que exige comando de preparo para funcionar deixou de funcionar na máquina de quem acabou de instalá-la.

flux:iterate fecha uma PR por execução. É eficiente rodar até três iterações independentes em
paralelo; quando a entrega passa desse tamanho, flux:land coordena o lote de múltiplas PRs,
ordena dependências e emite o go/no-go. flux:reply é standalone: pode ser chamado em qualquer
ponto para transformar um caso em comunicação embasada, não apenas depois do land.

Os comandos

Comando Entrada Saída Escreve?
flux:probe alvo(s) de telemetria (Sentry, Datadog) dossiê quantificado: distribuições, percentis, plausibilidade, cliente contra servidor e o cruzamento com o código vault; nunca cria issue, nunca muda estado na fonte
flux:refine ideia, thread do Slack, bug, ticket PRD + TRD + plano de slices no board, embasados em código real vault; nunca cria issue
flux:issue thread do Slack, texto livre, PR issue de alta qualidade, embasada via specialists rascunho no vault; cria no Linear só após aprovação
flux:build ticket Linear ou descrição + repo código + PR draft sim, via motor do repo
flux:peek working tree, branch, range, PR, doc, path parecer com badges no chat não (exceto --save)
flux:review PR ou doc review formal (holístico + specialists reconciliados) vault; posta quando você manda
flux:iterate PR correções aplicadas, réplicas postadas, threads resolvidas, CI vigiado sim (--dry rascunha read-only)
flux:land issue/feature multi-PR ordem de merge, validação de regressão, go/no-go mantém PRs merge-ready; nunca mergeia
flux:chain cadeia de elos (review>iterate) + alvo do primeiro elo validação da gramática antes de rodar, baton entre os elos, um banner por elo; cada elo mantém os próprios gates não escreve por conta; escreve o que cada elo escreve. Hoje executa só review>iterate
flux:reply permalink de thread rascunho Slack-safe + ata no vault salva rascunho; nunca posta sozinho
flux:equip repo motor de execução (L0) + suite de specialists local (L2) + L3 exposta sim, fora do repo alvo, pelo contrato de destino; manifesto só sob gate
flux:map nada (a máquina) inventário das lentes, delta desde a última execução, relatório de integridade o índice flux-agents.json; os consertos despacha ao equip, nunca escreve por conta

flux:equip e flux:map são os dois verbos fora do ciclo: nenhum trata de uma entrega. Os
demais elos consomem coisas que não produzem — o motor que o flux:build despacha e os specialists
que review/iterate/land reconciliam —, e é o equip que as cria quando faltam. Por isso
review, iterate, land e build não geram mais suite por conta própria: quando percebem a
falta, no fim do trabalho, oferecem o equip.

O flux:map é o que enxerga o conjunto. Todo elo verifica, no preflight, o que ele precisa para
aquele trabalho; ninguém olha a instalação inteira. Sem isso, uma suite quebrada, um manifesto
renomeado ou uma colisão de name: só aparece no meio de uma entrega, um elo por vez, sempre como
degradação e nunca como diagnóstico.

Pares que parecem iguais e não são

  • review vs iterate — review produz o parecer. iterate consome pareceres (inclusive de bots e humanos), verifica cada alegação contra o código real, aplica o que procede e defende o que não procede.
  • build vs /workflow do repo — build é o dispatcher: resolve repo e motor. O /workflow do repo é o motor: conhece os próprios testes, gates e padrão de PR. build nunca reimplementa motor.
  • iterate vs land — iterate fecha uma PR. land orquestra N PRs de uma entrega e delega o merge-ready de cada uma ao iterate.
  • probe vs refine — probe responde o que está acontecendo em produção, medindo eventos. refine responde por que isto importa e por onde começar, medindo escopo. Um bug de produção passa naturalmente pelos dois, nessa ordem, e os dois escrevem no mesmo board.
  • refine vs issue — refine responde por que isto importa, onde encosta e por onde começar, e pode recusar o pedido por tamanho. issue escreve o corpo da issue e a cria no tracker. Rodando os dois, o board é um só e a prospecção não se repete; rodando só o issue, nada se perde além do PRD e do TRD.

Arquitetura

flux/
├── README.md                       ← este arquivo (doc da família)
├── LICENSE                         MIT
├── examples/                       manifestos prontos: solo / time / pessoal
├── scripts/install-cursor.sh       instalação no Cursor (copia + prefixa os nomes)
├── .claude-plugin/marketplace.json o marketplace do Claude Code (o /plugin add lê este)
├── .cursor-plugin/marketplace.json o mesmo, para o Cursor
├── .agents/plugins/marketplace.json marketplace Git instalável pelo Codex
└── plugins/flux/                   ← ${FLUX_ROOT} quando instalado
    ├── .claude-plugin/plugin.json  manifesto Claude Code
    ├── .cursor-plugin/plugin.json  manifesto Cursor (mesmo corpo, outro harness)
    ├── .codex-plugin/plugin.json   manifesto Codex + metadata de interface
    ├── shared/codex-compat.md      adaptador de delegação nativa e capacidades opcionais
    ├── scripts/                    scripts bash/python que o plugin executa em runtime
    ├── agents/                      os agentes que a família despacha
    │   ├── pr-reviewer.md          o holístico genérico (default universal)
    │   ├── issue-creator.md        redige e cria issues aprovadas no tracker (sonnet, fan-out)
    │   ├── sentry-prospector.md    agrega os eventos de uma issue de telemetria (sonnet, fan-out)
    │   └── datadog-prospector.md   interroga logs/APM do backend por pergunta (sonnet, fan-out)
    ├── skills/                     ← os verbos (globais, context-agnósticos)
    │   ├── probe/                  opcional, antes do ciclo: investiga telemetria de produção
    │   ├── refine/                 opcional, antes do ciclo: fast SDD numa rodada
    │   ├── issue/  build/  peek/
    │   ├── review/  iterate/  land/  reply/  chain/
    │   ├── equip/                  fora do ciclo: motor (L0), specialists (L2), expõe L3
    │   └── map/                    fora do ciclo: levanta a instalação e grava o índice
    └── shared/                     contratos compartilhados (fonte única, não duplicar nos verbos)
    ├── preflight.md               verificação de pré-requisitos, níveis de capacidade, banner
    ├── api-first.md               transporte API primeiro, MCP como degrau declarado, por canal
    ├── hitl.md                    quando o elo para e pergunta, e como pergunta sem o tool preferido
    ├── flux-context.md            resolução de contexto via manifesto
    ├── agents-index.md            mapa das lentes na máquina (o que existe e onde, nunca o que rodou)
    ├── review-agents.md           descoberta + reconciliação de specialists
    ├── review-legend.md           badges canônicos dos findings
    ├── review-artifact-template.md formato do artefato de review no vault
    ├── review-body-template.md    formato do corpo da review postada no GitHub
    ├── pr-attribution.md          carimbo flux:<verbo>@<versão> na linha de atribuição da PR
    ├── issue-template.md          formato da issue do flux:issue
    ├── board-template.md          formato do board vivo (execução / iterate / delivery / conversa)
    ├── worktree-discipline.md     todo fluxo que escreve opera em worktree dedicado
    ├── write-destination.md       onde artefato gerado pode nascer: cascata + guardas de symlink/git/dotfiles
    ├── chain.md                  gramática de chains: verbo, artefato, legalidade, baton, falha no meio
    ├── scope-gate.md             medir o tamanho do pedido antes de gastar tempo com ele: sinais, faixas, corte proposto
    ├── run.md                     o registro local de uma execução (flux-run/1): layout, schema, níveis de garantia, privacidade
    ├── fanout-discipline.md       todo trabalho pesado vai para subagente, em paralelo
    ├── context-budget.md          leitura sob demanda, um root por sessão, delegação
    └── quality-gate-api.md        diagnóstico de gates Sonar via API (consultar em vez de deduzir)

O harness resolve skills/<verbo>/SKILL.md como /flux:<verbo>. Adicionar um diretório em skills/ publica um verbo novo, sem tocar em instalação.

O nome invocável é montado pelo harness, não escrito por nós. O mesmo skills/iterate/SKILL.md vira /flux:iterate num harness e pode virar outra forma em outro. Por isso os elos que despacham um irmão (o flux:land, que roda o iterate por PR dentro de subagente, e o flux:chain, que roda os elos em sequência) escrevem ${FLUX_CMD}iterate, com o prefixo resolvido e verificado pelo Passo 1b do preflight. O rigor é o mesmo do agente holístico: um nome de comando resolvido sem confirmação vira um subagente que não acha o comando e improvisa a iteração fora do contrato.

${FLUX_ROOT} é resolvido pelo preflight na ordem: ${CLAUDE_PLUGIN_ROOT} → ${CURSOR_PLUGIN_ROOT} → ${CODEX_PLUGIN_ROOT}, quando a sessão o define → o primeiro diretório acima da skill com .codex-plugin/plugin.json, que é como o Codex resolve na prática → dois níveis acima do verbo em execução, resolvendo symlink antes de subir (checkout direto, e a instalação local do Cursor) → ${FLUX_HOME} do ambiente. O contrato específico do Codex está em shared/codex-compat.md.

Esses nomes de variável são a única dependência de harness nos contratos compartilhados. Tudo abaixo do Passo 1 do preflight é escrito contra ${FLUX_ROOT} e ${FLUX_CMD}.

O manifesto de contexto

Um flux-context.json num .claude/ (ou .cursor/) de workspace ou repo. O comando procura o mais próximo subindo a árvore a partir do cwd, consultando .claude/ antes de .cursor/ em cada nível — mas proximidade sempre vence diretório. Achou → perfil declarado. Não achou → perfil genérico.

{
  "name": "acme",
  "holistic_reviewer": "acme-pr-reviewer",
  "doc_reviewer": "acme-doc-reviewer",
  "answerer": "acme-pr-answerer",
  "slack_prospector": "acme-slack-prospector",
  "slack_answerer": "acme-slack-answerer",
  "specialists_root": "~/agents/acme/{repo}/repo-owner.md",
  "vault_root": "~/notes",
  "vault_context": "acme",
  "workspace_root": "~/code/acme",
  "linear_org": "acme",
  "repos": ["backoffice", "rf-monorepo", "communication-api", "..."],
  "exec_command": "workflow",
  "exec_fallback": "acme:implement",
  "no_emdash": true
}

Contrato completo dos campos: shared/flux-context.md.

Perfil genérico (sem manifesto)

A família funciona sem configuração nenhuma. Sem manifesto, cada comando cai num default universal:

Aspecto Default sem manifesto
Reviewer holístico genérico da família, resolvido pela cascata do preflight (detecta a stack dinamicamente)
Specialists override local do repo: <repo>/.claude/agents/reviewer.md; sem isso, só holístico
Persistência não persiste; imprime no chat (--save <dir> no flux:review)
Motor de execução /workflow do repo; sem ele, o exec_fallback do perfil; sem ele, modo autônomo (worktree + AGENTS.md/CLAUDE.md do repo + checks + PR draft)
Travessão permitido (no_emdash: false)

Quem instala a família já tem review holístico e execução funcionando em qualquer repo GitHub. Declarar um flux-context.json é o que soma specialists, persistência no vault e integrações do time.

Convenções transversais

  • Falhar bem em vez de rodar mal — todo elo abre pelo preflight.md: verifica os requires declarados no frontmatter, resolve e confere a existência do agente holístico, e classifica o nível de capacidade (FULL / REDUCED / THIN / UNAVAILABLE). Faltou requisito hard → aborta sem efeito colateral. Faltou soft → roda e declara a perda no banner de perfil, que abre todo output. Um elo nunca improvisa um reviewer inline nem produz artefato fora do contrato de saída.
  • Badges canônicos — todo finding usa o vocabulário de review-legend.md: request-change, breaking-change, question, suggestion, praise, note. Cada um ancorado em arquivo:linha (código) ou §seção + trecho verbatim (doc).
  • Verificar antes de aceitar — nenhuma alegação de review (de bot ou de humano) é aplicada sem ser conferida contra o código real. Defender uma decisão correta é resultado válido.
  • Worktree sempre — todo fluxo que escreve código opera em git worktree dedicado à branch, nunca na árvore principal. Ver worktree-discipline.md.
  • Escopo medido antes do trabalho — elo que pode gastar minutos num pedido grande demais mede o tamanho dele antes, por sinais lidos do que já está em contexto e sem chamar agente para medir. Três faixas, e o gate propõe o corte em vez de só sinalizar. Ver scope-gate.md.
  • Destino de escrita verificado — artefato gerado fora do repo alvo (uma suite de specialists, um motor, um kit — tipicamente escritos pelo flux:equip) só nasce num destino que passou pela cascata e pelas três guardas de write-destination.md: symlink, repositório git e diretório gerido por dotfiles. Sem destino declarado o elo pergunta, não assume; nada existente é sobrescrito em silêncio; e o que foi criado fica registrado, para haver rollback.
  • Lente que existe é lente que roda — uma suite de specialists em disco e não invocável é dívida acionável, não estado normal. Quando a causa é a âncora (sessão aberta acima do repo ou em árvore irmã, que é o modo de quem trabalha num workspace com vários repos), o elo percorre a escada de alcance antes de degradar: acrescentar o diretório à sessão onde a capacidade existir e não houver colisão de name:, senão espelho namespaceado via ${FLUX_CMD}equip <slug> --expose-l3. O mapa do que existe na máquina vem do agents-index.md — que diz o que oferecer, nunca o que rodou: disponibilidade continua vindo só da lista de agentes da sessão.
  • Fan-out sempre — o contexto principal de um elo orquestra; investigar código, tocar repo, aplicar correção ou rodar outro flux:* vai para subagente, e unidades independentes vão em paralelo num único bloco. Na main ficam só parse, metadados baratos, HITL, board e watch. Regra pétrea, par simétrico do worktree: ver fanout-discipline.md.
  • Humano no volante nas fronteiras externas — nada é postado no GitHub, no Linear ou no Slack, nem mergeado, sem aprovação explícita.
  • pt-BR com acentuação correta no output; EN no código.
  • no_emdash — quando true, nada que possa acabar publicado (título/corpo de PR, comentário, mensagem de Slack) usa travessão ou en-dash.

Modo de sessão

A maioria dos elos quer workspace mode (cd <workspace_root> && claude), porque precisa navegar cross-repo. O flux:build funciona nos dois: em workspace mode você passa o repo como primeiro argumento; em repo mode ele infere do cwd.

Estender a família

Um verbo novo entra assim:

  1. Crie plugins/flux/skills/<verbo>/SKILL.md com frontmatter name / description / user-invocable: true.
  2. Abra com um Step 0-context que resolve o perfil via flux-context.md — nada de path ou agente de time hardcoded.
  3. Declare Out of scope explicitamente. A fronteira de cada elo é o que mantém o ciclo legível.
  4. Aponte os shared que se aplicam em vez de reescrever a lógica deles.
  5. Termine com handoff: qual elo vem depois, e por que.
  6. Registre o verbo na tabela Os comandos e, se ele mudar o ciclo, no diagrama.

Scripts auxiliares

Quando um verbo precisa de lógica determinística que não cabe em Markdown (polling, parsing de JSON), ela vira script. A convenção:

  • Onde. plugins/flux/scripts/ guarda o que o plugin executa em runtime e viaja com a instalação (só plugins/flux é copiado, por exemplo em scripts/install-cursor.sh). O scripts/ da raiz continua sendo manutenção do repo (checks, release, instalação) e não chega ao usuário.
  • Bash é o default. #!/usr/bin/env bash, set -euo pipefail, e dependência ausente sai com código 2 e mensagem em stderr, como em scripts/check-manifests.sh. Rode shellcheck antes de abrir PR.
  • Python só quando a lógica justifica (estrutura de dados, parsing que o jq não cobre, algo que o bash tornaria frágil). Use python3, apenas biblioteca padrão, versão mínima 3.8, e declare python3 como requisito.
  • Invocação explícita. Sempre bash "${FLUX_ROOT}/scripts/<nome>.sh" ou python3 "${FLUX_ROOT}/scripts/<nome>.py", nunca o caminho direto. Assim o script não depende do bit de execução, que nem toda instalação preserva. Dentro do script, resolva caminhos relativos ao próprio arquivo, não ao cwd.
  • Requisitos. O script não se autodeclara: o verbo que o chama declara o que ele precisa, no requires: do SKILL.md (bin: jq, bin: python3, em hard se o verbo não funciona sem ele, em soft se degrada) e, para o CLI, em VERB_REQUIREMENTS em cli/src/preflight.ts. O preflight avisa antes do verbo rodar; o script ainda confere a própria dependência e sai com 2.
  • Exemplo mínimo: plugins/flux/scripts/example.sh (exige jq).
  • Writer do run: plugins/flux/scripts/run.sh (bash e utilitários POSIX, mais iconv; sem jq nem git; por isso não entra no requires:, ver run.md) é o único que grava o ~/.flux/runs/<run_id>/; a CLI e as skills só o chamam. O contrato está em shared/run.md e o teste em scripts/test-run.sh.
  • Gate de polling do watch: plugins/flux/scripts/iterate-watch-gate.sh (exige gh e jq) faz fora da LLM o poll da PR e só sai quando há algo a fazer; o contrato de argumentos, eventos e códigos de saída está em --help. É lançado pelo watch do flux:iterate.

Propostas de tradução, novos comandos, agents, melhorias de acessibilidade, integrações e novos
engines/harnesses são bem-vindas. Antes de implementar uma mudança transversal, abra uma RFC
com a tese, escopo, dados ou exemplos que a sustentam,
alternativas e critérios de aceitação. Uma RFC pode virar PR, e uma PR pequena também pode ser
aberta diretamente quando a decisão já estiver clara.

Violeet, Violeeter e [GLabs]

O Flux é uma ferramenta irmã do ecossistema: Violeet é o produto, Violeeter é o sistema
visual, e Flux reutiliza essa linguagem com símbolo e wordmark próprios. [GLabs] é o guarda-chuva
que amarra esses produtos, usando a identidade visual compartilhada da família.

Veja a landing page para instalação, ciclo e contribuições.

Contribuindo

Antes de abrir PR, rode os checks. Eles pegam uma classe de erro que leitura não pega:

claude plugin validate .              # marketplace
claude plugin validate ./plugins/flux # plugin + frontmatter de cada skill
scripts/check-manifests.sh            # version e name iguais nos cinco manifests
scripts/check-codex-agent-contract.sh # o adaptador Codex continua descrito nos shared/
shellcheck plugins/flux/scripts/*.sh  # recomendado ao tocar em scripts (ver "Scripts auxiliares")
scripts/test-iterate-watch-gate.sh    # ao tocar em iterate-watch-gate.sh: gh e sleep falsos, sem rede e sem espera
scripts/test-run.sh                   # writer do run (run.sh): schema, permissões, recusa de path absoluto; roda em CI
(cd cli && bun test)                  # CLI, inclusive a paridade entre VERB_REQUIREMENTS e o requires: do review; roda em CI

Os dois validate conferem a forma de cada manifesto isoladamente, e recebem alvos disjuntos, então
nenhum dos dois enxerga .cursor-plugin/ nem .codex-plugin/. É por isso que o check-manifests.sh
existe: um bump que esquece parte dos cinco passa verde nos dois validate, e o mesmo corpo de skills
chega ao usuário com versão diferente conforme o harness. O check-codex-agent-contract.sh faz o
mesmo pelo texto dos shared/: é um canário que falha se a descrição do adaptador Codex sumir de
codex-compat.md, preflight.md ou review-agents.md. Os dois scripts rodam em CI
(checks.yml) a cada PR, então esquecer de rodá-los aqui custa uma
ida ao GitHub, não uma regressão publicada.

Sempre use aspas na description do frontmatter. Um : (dois-pontos seguido de espaço) num
valor YAML sem aspas quebra o parse, e o skill carrega com metadata vazia, silenciosamente:
sem name, sem description, sem user-invocable. O sintoma é um 1 error during load genérico
no /reload-plugins, sem dizer qual arquivo. O validate diz.

Publicar uma versão

Versão nova na main sem aprovação é landing desatualizada. A landing e a página de releases leem o
docs/latest-release.json, e só o workflow release.yml o atualiza.
O merge de uma versão nova dispara o workflow sozinho; o que falta depois dele é um clique de aprovação. Com dois bumps esperando, aprove um de cada vez, o
mais antigo primeiro: aprovados juntos, eles disputam o selo Latest e o docs/latest-release.json.
Antes era uma tag criada à mão, e foi esquecendo dela que as versões 1.32.0 a 1.38.0 saíram sem release
e a landing ficou parada em 1.31.0.

O fluxo completo:

  1. Na PR, bumpe a versão nos cinco manifests (.claude-plugin/marketplace.json,
    .cursor-plugin/marketplace.json e os três de plugins/flux/) e rode scripts/check-manifests.sh.
    Se quiser um resumo próprio na landing, ponha no corpo da PR as linhas Summary-en: e Summary-pt:,
    cada uma no começo da linha e fora de bloco de código, em até 180 caracteres e sem travessão. O
    limite e o travessão são convenção: o workflow copia a linha como está, sem validar nem cortar.
  2. Faça o merge na main. O push que toca o plugins/flux/.claude-plugin/plugin.json dispara o workflow
    release, e o job plan confere se a tag v<versão> já existe. Existindo, a run termina ali, sem
    pedir nada: o arquivo mudou sem a versão mudar.
  3. Aprove a run no Environment release (aba Actions, ou o link que o GitHub manda). É o único gate
    humano da release. O resumo da run mostra a mensagem exata que a tag vai levar: ela é montada antes
    do pedido de aprovação, e editar a PR depois disso não muda o que será publicado.
  4. Aprovada, a run cria a tag anotada v<versão> no commit do merge, publica a release e commita o
    docs/latest-release.json na main. Esse commit só acontece quando a versão é a corrente (guarda
    is_latest); uma versão mais antiga publica a release sem mexer na landing.

A mensagem da tag vira o changelog, e quem a escreve é o workflow:

<título da PR>

PR: <url da PR>

Summary-en: <a linha do corpo da PR, quando existe>
Summary-pt: <a linha do corpo da PR, quando existe>

O scripts/release-meta.sh lê os dois trailers. Sem eles, o resumo da landing cai na primeira linha, que
é o título da PR, igual nos dois idiomas e cortado em 180 caracteres; o valor de um trailer é publicado
sem corte. Num push direto na main, sem PR, a primeira linha é o assunto do commit.

Para conferir depois do merge:

gh run list --workflow release
git pull && cat docs/latest-release.json

O docs/latest-release.json deve trazer a versão nova. Sem essa linha, a landing não mudou.

Reparo

Três caminhos, e todos passam pela mesma aprovação. Os dois últimos são os gatilhos antigos, que
continuam existindo:

  • A run foi rejeitada, expirou sem aprovação ou falhou no meio. Reexecute só o que falhou
    (gh run rerun --failed <id>) e aprove. O --failed importa: um rerun completo refaz o plan, e se
    a tag já tinha sido criada ele conclui que não há o que publicar. Se o GitHub não deixar mais
    reexecutar a run (a janela é limitada), crie a tag à mão, como no último item.
  • A tag existe e a release não, ou a release saiu errada. Republique pelo dispatch:
    gh workflow run release -f version=<x.y.z>. O dispatch não cria tag: ele publica a que existe.
  • Tag de catch-up, ou mensagem escrita à mão. Crie a tag anotada e publique; o push dela dispara o
    workflow. Tag leve é recusada de propósito, e quem recusa é o workflow (o passo que busca o objeto da
    tag anotada), não o script isolado.
git tag -a v<x.y.z> <sha-da-main> -F <arquivo-com-a-mensagem>
git push origin refs/tags/v<x.y.z>

Uma tag por versão. Se versões ficaram sem tag, uma tag de catch-up na versão mais recente cobre as
puladas: o changelog dela deve dizer o que entrou desde a última tag.

O Environment release

O gate é um Environment
do GitHub com revisor obrigatório, e ele precisa existir antes de o workflow rodar: um job que
referencia um Environment inexistente o cria sem proteção nenhuma e publica sem pedir aprovação. Num
fork, crie o seu antes do primeiro bump (Settings, Environments, release, Required reviewers), com
"Prevent self-review" desligado se você é o único mantenedor.

Duas regras que valem para qualquer contribuição:

  1. Nada de contexto de time hardcoded. Se o seu time precisa de algo, isso vira campo do manifesto, nunca literal dentro de um verbo. O contrato está em shared/flux-context.md.
  2. Degradar bem em vez de rodar mal. Toda capacidade nova entra com o caminho de ausência definido e declarado no banner de perfil.

Construído com flux:

  • Violeet — terminal macOS que roda vários agentes de IA
    como abas de uma janela só, com o HITL na sidebar. O fan-out da família fica visível ali:
    uma aba por agente.

Licença

MIT.

Reviews (0)

No results found