Versão
v1.2.23
O que foi entregue, em números
- 82
- PRs integrados
- 132,379
- Linhas adicionadas
- 48,021
- Linhas de código
- Código
- 48,021
- Testes
- 48,923
- Docs
- 35,435
- Soma · código + testes + docs
- 132,379
de 82 integrados
- bug 34 41%
- feature 26 32%
- polish 0 0%
- docs 16 20%
- groundwork 0 0%
- unclassified 6 7%
desde v1.2.22 · tag em
A carta
A carta do fundador, na íntegra
Oi,
A v1.2.23 acaba com o FlowForge refazendo um trabalho que já tinha terminado. Um ticket foi mesclado, e quinze segundos depois o pipeline gerou para ele um novo worker e iniciou o timer dele — três vezes em dois dias; o ponto de estrangulamento do spawn já classificava o ticket como owned-in-lane e só registrava isso em log, então agora ele recusa o spawn antes da sessão do tmux, do processo do modelo ou do início do timer faturável, e remove o worktree que criou (#6286). Um push que anularia uma revisão GOLDEN também é recusado, com a rodada de revisão e o custo que ele teria anulado nomeados, e um motivo registrado é exigido para prosseguir (#6111). Um hotfix que chegava na main costumava ficar só ali — em 2026-09-13 a lane aberta ficou treze commits atrás por onze horas até uma sincronização ser rodada à mão; o loop do autofire agora traz a main para dentro da lane sozinho, ao final de toda passada (#6220). E um sprint com data de término e sem data de início costumava passar na auditoria — toda porta de sprint agora recusa um sprint sem uma das duas datas, e o flowforge sprint-audit lê todo ticket de um sprint, aberto e fechado (#6302, #6313).
O que mais me orgulha é o Release Letters. A v1.2.22 anunciou isso para a v1.2.23 — uma carta de versão e uma página de versão construídas a partir das suas próprias notas de versão, enviadas para a sua própria lista de clientes, opt-in, em Configurações, desligado por padrão — e chegou. Um estudo ratificado (#6219) e um ADR de costuras (ADR-0137) sustentaram isso, como quinze fases numa única lane (#6229): todo corte te entrega um .eml pronto para enviar sem nada configurado (#6230, #6231), e Configurações → Release Letters (ou flowforge marketing set) permite apontar um remetente — Resend, ou seu próprio relay SMTP (#6237) —, um host de imagens (#6236), seus destinatários (#6238) e seu cancelamento de inscrição (#6239) para a sua própria lista, tudo sem a FlowForge hospedar nada disso para você.
Mais uma coisa: os sprints agora carregam suas próprias datas de início e término (#6302, #6313), um plano ratificado chega pavimentado e é disparado num sprint com datas, com seu épico e seus tickets, num único comando (#6301, #6314), e épicos, milestones, sprints e iniciativas se fecham sozinhos no instante em que todo filho está concluído — ninguém precisa perguntar (#6290). Se algo aqui quebrou para você, ou melhorou sua semana, responda e me conte. Eu leio cada uma.
Um abraço, Alex
Release Letters — o pipeline da carta passa a ser seu agora

A v1.2.22 anunciou isso para a v1.2.23: "uma carta de versão e uma página de versão geradas a partir das suas próprias notas de versão, enviadas para a sua própria lista de clientes … opt-in, em Configurações, desligado por padrão." Chegou. Um estudo ratificado (#6219) e um ADR de costuras (ADR-0137) sustentaram isso, como quinze fases numa única lane (#6229).
Todo corte pode te entregar uma carta pronta para enviar sem nada configurado. O flowforge release letter render <version> constrói uma renderização HTML segura para e-mail, de 600 pixels, e uma gêmea em texto simples a partir do seu LETTER.md e dos tokens de marca do seu projeto — sem precisar de designer, e uma renderização feita à mão nunca é sobrescrita sem --force (#6231). O flowforge release letter export <version> então grava render/LETTER.eml (e uma gêmea .pt-BR.eml quando o pacote tem uma): uma mensagem compatível com o padrão que qualquer cliente de e-mail abre como rascunho e envia, sem ler nenhum remetente, chave, host ou lista de destinatários para produzi-la (#6230).
Configurações → Release Letters é a nona aba de Configurações: remetente, host de imagens, destinatários, cancelamento de inscrição e o rodapé jurídico, cada um uma costura que você possui — a FlowForge não hospeda nada para você. A entrega vem desligada por padrão; um segredo que você digita é gravado no keychain do sistema operacional e nunca no settings.toml, não ecoa nada enquanto você digita ou cola, e não existe revelação (#6235, #6240). As costuras por trás disso: o remetente é o Resend, ou seu próprio relay SMTP (#6237); o host de imagens é um bucket S3 atrás de um CDN ou um diretório que você já serve, comprovado com um GET real que precisa responder com uma imagem, não uma página de erro (#6236); os destinatários vêm de um arquivo CSV, uma lista manual, ou uma consulta ao Supabase, cada linha carregando seu locale e estado de consentimento, sem nenhum endereço jamais impresso ou registrado em log (#6238); o cancelamento de inscrição é um link de um clique, um mailto:, ou nenhum, e o rodapé diz qual (#6239).
A mesma tabela é legível pela linha de comando: flowforge marketing get/set, flowforge marketing test images|sender|recipients|unsubscribe, e flowforge marketing preflight <version> — SPF, DKIM, DMARC, tamanho do HTML, todo link, campos de mesclagem, e o diff entre texto e HTML, nada disso jamais bloqueia um envio (#6241, #6239). O envio em si roda no flowforge release promote, depois da virada, assim que as páginas estão no ar: uma semente (seed) para você, um y/N para o lote, lotes sob um teto diário, e um log de envio que permite que uma nova rodada pule todo mundo que já aceitou; uma configuração partial recusa o envio, nunca o promote (#6242, #6244). O flowforge doctor ganhou as linhas marketing e marketing-dns (#6235, #6241), e um guia para o cliente percorre os quatro incrementos em inglês e em português do Brasil: documentation/2.0/guides/marketing-settings.md (#6244).
O pipeline para de refazer trabalho já entregue
Um ticket mesclado ganhava um novo worker e um novo timer quinze segundos depois — três vezes em dois dias — porque o ponto de estrangulamento do spawn já classificava o ticket como owned-in-lane e só registrava isso em log. Agora ele recusa o spawn antes da sessão do tmux, do processo do modelo e do timer faturável, e remove o worktree que criou, a menos que o ticket tenha sido reaberto ou seja um épico (#6286).
O dreno de ondas (wave drain) agora lê "mesclado" a partir do próprio registro do pipeline de merge: no intervalo de doze segundos entre um merge aposentar seu worker e o cockpit perceber, o dreno costumava ler o ticket como enfileirado e disparava de novo — a origem de toda linha BRIEF UNDELIVERED … can't find pane (#6053). As rodadas de onda avançam sozinhas: uma rodada esperando por uma vaga livre de worker não é mais aposentada como resíduo depois de 30 segundos, uma rodada cujo cockpit morreu há menos de uma hora é adotada pela próxima, e a tela de ondas nomeia claramente o próximo passo (#6065).
Um hotfix na main agora desce sozinho para a lane aberta — em 2026-09-13 a lane ficou 13 commits atrás por onze horas até uma sincronização ser rodada à mão; o loop do autofire traz a main para dentro da lane ao final de toda passada, registrando toda tentativa em merge-advance.log (#6220). Um push que anularia uma revisão GOLDEN é recusado: medido na máquina do fundador ao longo de duas semanas, 220 vereditos GOLDEN foram vinculados e 42 anulados por um push posterior; o hook de pre-push agora nomeia o veredito e a rodada de revisão que isso custaria, e exige um motivo registrado para prosseguir (#6111). Um veredito que ninguém reconheceu também é medido agora — o flowforge review unacked e uma linha verdict-unacked do doctor relatam todo veredito sem remediação além de um limiar (#6103).
Um worker bloqueado em algo que só o fundador pode rodar agora avisa o fundador com o pedido exato (#5837), uma escalada vinda do ator de estagnação (stall actor) nomeia seu autor e nunca sobrescreve um aviso que uma pessoa já deixou (#6117), e a ACE limpa toda marca de worker e todo terminal estranho ao iniciar, para que um cockpit descartável nunca herde a identidade de um worker (#6281). O wall da mensagem de commit agora lê origin/<base>..<head> direto do git em vez da lista de commits de PR em cache do GitHub, então ele nunca recusa commits que a base já contém (#6221). E um épico é decidido pelo que o ticket declara — kind= tem prioridade sobre uma etiqueta no título, tanto para o fechador quanto para o motor de ondas (#5757, #6152).
Sprints carregam suas datas, e contêineres terminados se fecham
Um sprint podia existir com uma data de término e sem data de início — o milestone 191 foi criado assim, recebeu tickets, e o sprint-audit o aprovava porque a auditoria lia só os tickets abertos e nunca checava a data de início. Toda porta de sprint agora recusa um sprint sem uma das duas datas — o formulário de milestone do cockpit, suas teclas de converter-em-sprint, e o feature emit --live — antes de qualquer chamada chegar ao seu sistema de tickets. O flowforge sprint-audit lê todo ticket de um sprint, aberto e fechado. O flowforge sprint-dates é o único corretor: dry-run por padrão, --derive-due usa o término do ticket mais tardio, recusado enquanto qualquer ticket estiver sem data. Sprints criados antes de 2026-06-29, quando a regra foi ratificada, são classificados como legacy e avisados, nunca recusados; a linha sprint-dates do flowforge doctor separa os dois casos (#6302, #6313).
Épicos, milestones, sprints e iniciativas se fecham sozinhos assim que todo filho está concluído — ninguém precisa perguntar. Um ticket de épico conta como estrutura, nunca como item de trabalho, em toda contagem: o percentual, os pips da lane, o cabeçalho e o auto-fechador, e um contêiner a 100% nunca aparece sob o ▼ Active da War Room. Os fechamentos de contêiner rodam a partir de código na branch padrão — a Action de merge e uma varredura de 30 minutos — então eles começam assim que esta versão estiver na main (#6290).
Agora um plano vem em dois tipos: pavimentado, depois disparado. Aterrissar um plano ratificado (flowforge doc ratify --land, flowforge plans land) não cria mais um sprint — ele pavimenta o plano como um milestone sem datas na prateleira, com documentos e um DAG, sem início, sem prazo e sem tickets (#6314). O flowforge plans fire <plano> --begin AAAA-MM-DD transforma esse plano no seu sprint e nos seus tickets: recusa a menos que o plano carregue uma ratificação na sua revisão atual, pergunta a data de início em todo primeiro disparo e nunca a deduz, e então — com --live — converte o milestone num sprint com seu início e seu término derivado antes de existir qualquer ticket, cria o épico e um ticket por unidade de trabalho em ordem de dependência, com seus trailers Depends-on:, Duration: e de gate, e grava as datas deles. O --into <sprint> dispara um plano como épico dentro de um sprint que você já tem, toda recusa é reunida numa única passada, e um disparo interrompido no meio mostra o comando que o retoma. O flowforge plans lint <doc> roda a mesma derivação sem gravar nada; o flowforge ticket new --study --phase … --phase … cria o épico de um estudo e suas fases com gate num único passo (#6301, #6314).
A prateleira "Plans ready to fire" agora existe por construção: as notas da v1.2.22 diziam que ela era criada pela instalação, e não era — uma instalação da 1.2.22 respondia shelf absent até dois verbos serem digitados à mão. O flowforge install e o flowforge update agora a entregam para todo projeto registrado, e o cockpit a entrega uma vez por versão instalada em segundo plano (#6197). A leitura de desvio (drift) da prateleira agora avalia contra a lane do seu remoto, não do seu checkout — um checkout 275 commits atrás costumava ler todo plano como ○ unknown; a leitura agora resolve origin/<lane> primeiro e anota (checkout N behind) (#6198). E sprints da prateleira aparecem como ◇ SPRINT na coluna TYPE da War Room, onde antes apareciam como ○ unknown, com o nome de um sprint não repetindo mais a própria data (#6280).
Telas que se explicam

O ? agora abre uma legenda de dentro do Gantt: todo glifo e todo termo de cabeçalho — folga total, folga livre, adiantamento salvo, depende de, hoje, término, caminho crítico, velocidade, carga — ganha uma frase, extraída das próprias constantes com que a tela é desenhada, e ? legend entra no rodapé em toda largura (#6248). O b filtra o Gantt do mesmo jeito que a War Room — All, In play, Live, Planned — mudando só as linhas desenhadas, nunca o caminho crítico, a folga, a carga ou a inteligência de sprint calculada sobre o sprint inteiro; na visão de equipe, o o abre um seletor de desenvolvedores com seleção múltipla (#6254). Tickets concluídos agora chegam ao Gantt em todo tipo de provedor — um projeto kind: ff costumava ler só tickets abertos, então um ticket terminado sumia do próprio sprint (#6253). E uma linha de proposta de sprint propõe um posicionamento guloso (greedy) do trabalho aberto dentro do sprint e depois dele, e nunca grava uma data (#5595).
A linha de título da War Room agora carrega um slot de estado de carregamento — ■ as of 12:00Z, ⋯ loading, ◔ stale, ◧ partial — open tickets, □ failed — offline — glifo e palavra, nunca só a cor. Uma leitura ausente ganha um aviso nomeado, seus números dependentes mostram — em vez de um zero silencioso, e r recarrega o quadro inteiro no lugar, mantendo seu cursor, escopo e filtros; uma visão filtrada diz filtered · N of M sprints shown, para que uma lista quase vazia nunca pareça um carregamento que falhou (#6297). A legenda também nomeia todo círculo — ◉ épico, ◇ sprint, ▣ iniciativa, nenhum deles uma onda — e os glifos de estado de worker são desenhados só no painel Workers, nunca numa linha de ticket da War Room (#6073).
Colado
Colado é um termo do jiu-jitsu — uma posição está colada quando está justa, perfeitamente ajustada, sem folga, pressão máxima. É o nome da família de gates da FlowForge que não deixam espaço nenhum entre a regra e o trabalho. Esta versão fecha estas lacunas, cada uma uma porta que agora recusa em vez de uma linha que só registrava em log:
- Um ticket entregue não pode mais ser gerado de novo — o spawn é recusado antes de qualquer timer começar (#6286).
- Um push não pode mais anular silenciosamente uma revisão GOLDEN — ele é recusado, com o custo nomeado, e só prossegue com um motivo registrado (#6111).
- Um sprint não pode mais ser criado sem suas datas de início e término — em toda porta de sprint, com a auditoria lendo todo ticket (#6302, #6313).
- Uma versão não pode mais ser cortada sem sua carta ou um motivo registrado (#6212), nem com uma mudança de elenco que suas notas não nomeiam (#6201).
- O wall da mensagem de commit não pode mais recusar commits que a base já contém, porque ele lê o intervalo direto do git (#6221).
Coisas singelas que mudam tudo
Nem toda mudança merece destaque. Cada uma cabe numa linha, e você a sente todo dia.
- Favoritas de rádio ficam marcadas já no primeiro toque de
f— um segundo toque costumava desmarcar em silêncio o que o primeiro toque nunca chegava a salvar de forma visível (#6199). - Sprints da prateleira aparecem como sprints, e seus nomes param de repetir a data (#6280).
- O
flowforge doctorlê o prompt de consentimento do Claude Code para acesso fora do diretório de trabalho (2.1.257 em diante) e nunca responde por você: um worker que ninguém está observando fica parado nesse prompt até um humano responder, então a linhaclaude-outside-readrelata se ele ainda está armado nesta máquina, e a ACE registra uma linha em log antes de uma onda quando está (#5897).
Um passo de configuração
- O Release Letters só envia o que você configurar. Sem nada configurado, o corte te entrega um
.emle essa é a entrega inteira. Um envio precisa de um remetente (uma chave do Resend ou um relay SMTP), e uma carta com imagens precisa de um host de imagens; destinatários e cancelamento de inscrição completam o quadro. Cada um se configura em Configurações → Release Letters ou comflowforge marketing set, e oflowforge doctornomeia o que ainda estiver faltando. Uma fonte de destinatários no Supabase também precisa de uma função de leitura no seu próprio projeto Supabase (#6235–#6239). - O ajuste de migração de consentimento de marketing (#6183) entra no ar quando é aplicado ao banco de dados a que pertence.
Ainda não
- O próprio botão "enviar um teste para mim" da aba Release Letters ainda não está conectado. Ele responde
✗ not sent · no sender provider is in this build yet— nada é enviado. O remetente em si já está construído: oflowforge marketing test sendero testa e envia essa única mensagem de teste. A aba oferecenoneeresendcomo provedores — um relay SMTP se configura comflowforge marketing set— e sua linha de veredito aponta paraflowforge marketing status, que não é um verbo; oflowforge doctor(linhamarketing) e oflowforge marketing getdão a mesma resposta (#6240, #6237). - A prévia de voz ainda espera por uma versão do motor de voz. Toda instalação hoje roda o motor fixado que não consegue pré-ouvir outra voz; escolha e salve para ouvir uma. O espectro do rail se movendo com os níveis reais da voz da ACE, e a saída do sidecar quando seu cockpit morre, já estão mesclados do lado do cockpit e ligam junto com essa versão (#6202, #5725, #6208).
- O próprio
get.flowforgesoft.com/ainda responde com uma página de acesso negado. O redirecionamento para a página de versões está escrito e testado, e entra no ar quando sua mudança de infraestrutura for aplicada; os caminhos de instalação e atualização não são afetados (#6191). - Desenhado nesta versão, não construído nela: uma regra única de ritmo para atrasado/adiantado/em risco/percentual concluído (ADR-0138, #6294); as fases 2 e 3 da leitura da Fleet para a fila de Workers (#6139, #6140); o estudo de contrato de dados e API da War Room do console, com seu plano e DAG (#6299, #6300); e as fundações de escopo de épico, entregues sem nenhuma mudança de tela ainda (#6151, #6153).
Agentes
Nenhuma mudança de elenco nesta versão: a FlowForge instala os mesmos 44 especialistas que a v1.2.22 entregou (git diff --name-status -M v1.2.22 origin/release/1.2.23 -- v3/packages/core/agents está vazio).
Atualizar
flowforge updatenuma instalação já existente, oucurl -fsSL https://get.flowforgesoft.com/install.sh | shpara uma nova. Os dois caminhos gravam o mesmo binário de release em/usr/local/bine~/.flowforge/binjuntos. Oflowforge version updatenão atualiza nada — ele imprime a versão instalada e sai.
Os números desta página são uma leitura pontual de v3/site/src/data/release-stats.json, chave "v1.2.23" (computed_at: 2026-09-14T18:50:06Z), intervalo v1.2.22 (dba4a1754, com tag em 2026-09-13T01:31:23-04:00) → lane head 902388999 — a v1.2.23 ainda não tem tag, e estas cifras serão re-derivadas na tag antes do corte.