CommunityEscrita e Ediçãogithub.com

mariagorskikh/product-changelog

Escreva e envie um e-mail recorrente de changelog de produto para seus usuários, depois publique o tópico correspondente no X, post no LinkedIn e anúncio na comunidade (Discord ou Slack), e opcionalmente esboce um vídeo animado de changelog.

O que é product-changelog?

Esta skill automatiza o ciclo completo de criação e distribuição de changelogs de produto. Ela começa com uma configuração única inicial, perguntando ao usuário detalhes como nome do produto, URLs, destinatários de teste e configurações do provedor de e-mail (Resend). Uma vez configurada, a skill opera de forma autônoma (padrão) ou em modo de revisão, gerando cada issue de changelog sem aprovação adicional, exceto para ações que envolvem custos financeiros reais. O processo inclui a coleta de mudanças visíveis ao usuário a partir de git e notas de release, redação do e-mail seguindo regras de voz e formatação predefinidas, criação de screenshots, linting do conteúdo, envio de teste com leitura de retorno, construção da audiência respeitando opt-outs, envio para todos os usuários (via broadcast ou individualmente), verificação de entrega, e publicação de posts sociais (X, LinkedIn, Discord/Slack). A ferramenta também suporta a criação opcional de um vídeo curto de changelog. Todo o processo prioriza a segurança legal e técnica, com paradas forçadas para problemas como falhas de lint, links quebrados ou violações de regras de opt-out. A habilidade é particularmente útil para PMs, founders e equipes de produto que desejam comunicar mudanças de forma consistente e eficiente, economizando horas de trabalho manual a cada ciclo de release.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/mariagorskikh/product-changelog/tree/HEAD

Installed? Explore more Escrita e Edição skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Changelog de produto

Um e-mail recorrente que conta aos usuários o que mudou no produto, escrito como uma pessoa, enviado com segurança e depois reutilizado para posts sociais. O e-mail é a fonte da verdade para cada edição; todos os outros canais são derivados dele.

Como esta skill funciona

  • Pergunte uma vez, no início. Na primeira execução (ou quando a configuração estiver faltando ou um valor necessário estiver em branco), faça as perguntas de configuração em um lote curto, escreva config.yaml e continue sem mais perguntas.
  • Então faça tudo. No modo autonomy.mode: autonomous (o padrão), você seleciona os itens, rascunha, faz lint, auto-revisa, captura screenshots, envia teste, lê o teste de volta, constrói a audiência, executa um dry run, envia para todos, verifica, puxa os opt-outs, escreve e publica os posts sociais e arquiva. Nenhuma etapa de aprovação. Cada ação externa passa por um portão de auto-revisão primeiro.
  • Dinheiro é a única aprovação. Qualquer coisa que custe dinheiro aguarda o "sim" explícito do usuário no chat, em todos os modos: um envio que excederia a cota incluída no plano do provedor (provider.monthly_quota), atualizar o plano do provedor, comprar um domínio, ferramentas ou licenças pagas (por exemplo, uma licença paga da Remotion Company). Nada mais precisa de um "sim".
  • Paradas forçadas não são aprovações. Elas interrompem aquela ação específica. Termine o que for seguro e relate. Veja Paradas forçadas.
  • Relate no final. Um resumo: o assunto e o texto completo que foram enviados, contagens (na fila, enviados, falhos, excluídos, cancelados), amostra de entrega, resultado da leitura de retorno do teste, cada post com seu link, o que foi pulado e por quê.
  • Modo review mantém os antigos portões de aprovação por ação. Veja Modo de revisão.

Cada script é um dry run por padrão. Envios reais precisam de flags explícitas (--send, --yes-send-to-everyone, --yes-send-broadcast). No modo autônomo, você mesmo as passa, e só depois que o portão de auto-revisão correspondente for aprovado. Nunca envie e-mails ad hoc fora dos scripts, porque os scripts são o que garantem a exclusão de opt-outs.

Etapa 0: carregar a configuração

  1. Procure por config.yaml na raiz do projeto atual, depois na pasta desta skill (ou $CHANGELOG_CONFIG).
  2. Se não houver, copie config.example.yaml para config.yaml na raiz do projeto e pergunte, em uma única mensagem:
    • nome do produto, site, URLs do dashboard e da documentação
    • nome e cargo do remetente, endereço de envio, reply-to
    • destinatários de teste (nomes e endereços)
    • provedor: o ID da audiência do Resend, a variável de ambiente que contém a chave da API e os e-mails mensais incluídos no plano, se souberem (provider.monthly_quota, opcional)
    • modo de cancelamento (broadcast ou own_endpoint)
    • hospedagem de imagens: para onde vão os screenshots e sua URL base pública
    • opcional: cadência, cor do link da marca e como postar em cada canal social (social.post_via) Não adivinhe nenhum deles. Escreva as respostas no config.yaml e continue.
  3. Qualquer valor ainda definido como um placeholder em MAIÚSCULAS ou um endereço yourproduct.example é considerado ausente.
  4. Leia autonomy.mode (padrão autonomous), voice.notes e voice.banned_phrases. As configurações de voz substituem os padrões nas referências.
  5. Segredos nunca vão para a configuração ou para o chat. Chaves de API e a chave secreta de cancelamento de assinatura ficam em variáveis de ambiente.

Edições posteriores não perguntam nada. A única pergunta opcional é "Algo foi enviado fora do git desta vez (preços, parcerias, documentação)?" Se o usuário não estiver por perto, pule e trabalhe a partir do git e das notas de release.

Etapa 1: escolher o que incluir

Leia references/voice-and-format.md primeiro.

  • Encontre a última edição em paths.issues_dir (pastas nomeadas NNN-YYYY-MM-DD-slug). A mais nova é o modelo para a próxima.
  • Reúna candidatos desde essa data: git log --since=<data> --no-merges --oneline, pull requests mesclados, notas de release, além de qualquer coisa que o usuário mencionou.
  • Mantenha apenas mudanças visíveis ao usuário. 3 a 5 itens, classificados por utilidade para o leitor. Comece com a mudança mais útil, aquela que a maioria dos leitores pode usar hoje.
  • Verifique cada afirmação com o produto e site ao vivo. Nunca invente um recurso, um número ou uma data. Se uma afirmação não puder ser verificada, descarte o item.
  • Escreva a lista e a ordem no arquivo NOTES.md da edição e prossiga.

Etapa 2: rascunhar o e-mail

Crie paths.issues_dir/NNN-YYYY-MM-DD-slug/ e escreva:

  • subject.txt: focado no benefício e no produto primeiro ("Agora você pode exportar relatórios para o Sheets"). Nunca "Changelog #N".
  • email.html: a partir de templates/email.html (ou da última edição), preenchendo todos os marcadores [[...]] com a configuração e o conteúdo.
  • email.txt: as mesmas palavras em texto simples com URLs puras.

Mantenha {{NAME}} e {{UNSUB_URL}} como placeholders literais; os scripts de envio os preenchem por destinatário.

Regras principais (detalhes na referência):

  • Olá {{NAME}},, depois a linha de abertura de uma linha da configuração, em seguida direto ao item principal.
  • Cada item: o que mudou, depois por que é importante, em frases fluidas. Sem bullet points rotulados.
  • Frases curtas, palavras simples, "agora você pode" em vez de "nós construímos".
  • No máximo um destaque em negrito por parágrafo.
  • No máximo um screenshot por item; o item principal sempre recebe um, e ele linka para o recurso.
  • HTML minimalista e estilizado: wrapper de 600px, fonte do sistema, estilos inline, sem botões ou banners.
  • Sem "animados em anunciar" e o resto da lista proibida. Sem travessões ou travessões longos se voice.no_dashes estiver ativo.
  • P.S. casual opcional ("A propósito, ...").
  • Assinatura da configuração. A linha de cancelamento é a última linha, pequena e discreta.

Etapa 3: screenshots

Siga references/screenshots.md: prepare um estado real em uma conta de demonstração (sem dados de clientes), capture em 2x com Playwright, recorte para o painel, nomeie os arquivos <issue>-<slug>.png, hospede-os em paths.image_base_url e confirme que cada URL retorna 200 antes de qualquer envio.

Etapa 4: lint e auto-revisão (portão 1: cópia)

python3 scripts/lint_email.py ISSUE_DIR --check-links

Corrija todas as falhas e depois percorra esta lista de verificação. Corrija e reexecute até que cada item passe.

  • lint_email.py --check-links sai com código 0.
  • Leia de cima para baixo como um cliente ocupado: a mudança mais útil está clara em 5 segundos.
  • Cada item é algo que um usuário pode ver ou usar hoje.
  • Cada afirmação, número e link corresponde ao produto e site ao vivo.
  • Nada parece um press release; soa como o remetente falando.
  • Assunto com menos de 60 caracteres, focado no benefício, sem "Changelog #N".
  • Cada imagem tem texto alternativo e sua URL hospedada retorna 200 (ou será implantada antes da Etapa 7).

Etapa 5: envio de teste e leitura de retorno (portão 2: cópia entregue)

python3 scripts/send_test.py ISSUE_DIR --send      # apenas para test_recipients, prefixo [TEST]
python3 scripts/send_test.py ISSUE_DIR --readback  # um minuto depois

Cópias de teste vão apenas para test_recipients e incorporam imagens inline se ainda não estiverem implantadas. --readback puxa cada mensagem entregue da API do provedor e verifica o último evento, o assunto, a saudação renderizada e a linha de cancelamento, e que nenhum placeholder sobreviveu. Leia o HTML retornado você mesmo uma vez. Se algo estiver errado, corrija, refaça lint, reteste.

No modo own_endpoint, abra o link de cancelamento da cópia de teste, confirme que o opt-out foi registrado e depois reassine o endereço de teste.

Etapa 6: construir a audiência

Detalhes completos em references/sending.md.

  • Construa ISSUE_DIR/audience.jsonl do zero a partir do banco de dados do usuário ({"email", "name"} por linha). Nunca reutilize uma lista antiga.
  • Construa ISSUE_DIR/unsubs.txt a partir da tabela de opt-out. No modo broadcast, primeiro execute python3 scripts/broadcast_unsubs.py --out <issues_dir>/unsubs.txt e copie-o.
  • Fundadores, contas de teste e demonstração estão na configuração exclude; eles recebem cópias de teste.

Etapa 7: enviar para todos (portão 3: audiência)

Escolha o caminho a partir de unsubscribe.mode. Execute o dry run primeiro e verifique as contagens.

Modo Broadcast (provedor hospeda o cancelamento):

python3 scripts/broadcast_sync.py ISSUE_DIR/audience.jsonl            # plano
python3 scripts/broadcast_sync.py ISSUE_DIR/audience.jsonl --apply    # upsert contatos
python3 scripts/broadcast_create.py ISSUE_DIR --create                # apenas rascunho
python3 scripts/broadcast_create.py --send BROADCAST_ID               # mostra a contagem de destinatários, recusa
python3 scripts/broadcast_create.py --send BROADCAST_ID --yes-send-broadcast

Modo de endpoint próprio (links assinados para sua própria página):

python3 scripts/blast.py ISSUE_DIR                                    # dry run com contagens
python3 scripts/blast.py ISSUE_DIR --send --yes-send-to-everyone

Lista de verificação da audiência, tudo deve passar antes da flag de envio:

  • Os portões 1 e 2 passaram nesta cópia exata (nada mudou desde a leitura de retorno).
  • A lista de opt-out foi puxada ou construída nesta execução e está não vazia se o produto já teve algum cancelamento.
  • As contagens do dry run fazem sentido: enfileirados está próximo de usuários menos opt-outs menos excluídos; nenhum salto surpresa em relação ao NOTES.md da última edição.
  • Modo broadcast: broadcast_sync.py não relatou contatos obsoletos inesperados.
  • Cada URL de imagem hospedada retorna 200.
  • Cota: se provider.monthly_quota estiver definido, passe --sent-this-month N (some as contagens de envio deste mês no NOTES.md da edição mais outro e-mail no mesmo plano, se conhecido). Se o script disser que o envio excederia a cota, pare e pergunte ao usuário; passe --yes-over-quota apenas após o "sim" explícito dele.

O envio individual é retomável: se parar, reexecute o mesmo comando e ele pula os endereços já enviados.

Etapa 8: verificar e sincronizar

  • Individual: python3 scripts/verify_delivery.py ISSUE_DIR --sample 40. Broadcasts: GET /broadcasts/{id} através da API do provedor ou do painel.
  • Puxe os opt-outs de volta após um dia (broadcast_unsubs.py). Se o usuário mantiver os opt-outs em seu próprio banco de dados e você tiver acesso de escrita, importe-os; caso contrário, informe no relatório.

Etapa 9: posts sociais

Escreva a partir do e-mail final, seguindo references/social.md:

  • X thread: tweet de gancho começando com social.hook_prefix que nomeia cada item, sem link, screenshot mais forte. Depois um tweet numerado por item com seu link e screenshot. Plus uma citação pessoal de uma linha para um fundador.
  • LinkedIn: um post, gancho na primeira linha, um parágrafo curto por item, texto simples, galeria de imagens.
  • Comunidade (Discord ou Slack): linha de abertura, uma linha por item com um link puro, o link da thread quando estiver ao vivo.

Máximo de 4 a 5 itens, sem avisos de política, afirmações correspondem ao site ao vivo. Execute as mesmas verificações de frases proibidas e travessões em social.md (lint_email.py o lê). Depois, para cada canal com uma ferramenta em social.post_via, publique você mesmo e registre a URL do post. Para canais sem ferramenta, entregue ao usuário o texto final e as imagens. A postagem de citação do fundador é de uma conta pessoal, portanto, entregue-a a menos que uma ferramenta para essa conta esteja configurada.

Etapa 10: vídeo (opcional, apenas sob solicitação)

Se o usuário pedir, siga references/video.md: um reel de movimento de 15 a 25 segundos a partir dos screenshots da edição, sem slide de título, manchete grande por item, screenshots dominam, encerramento com a URL do produto. O Remotion precisa de uma licença paga da empresa acima de um certo tamanho de equipe; isso é uma questão de dinheiro para o usuário.

Etapa 11: arquivar e relatar

Na pasta da edição, mantenha: subject.txt, email.html, email.txt, os screenshots, social.md, test_results.jsonl e um NOTES.md com a lista de itens, data de envio, caminho usado, tamanho da audiência, contagens de enviados e falhos, ID do broadcast, URLs dos posts e cancelamentos após um dia. Se o produto tiver uma página pública de changelog web (product.changelog_page) e sua fonte estiver neste repositório, adicione a edição lá também. Quando o usuário corrigir a voz ou formatação, adicione a lição a voice.notes na configuração para que a próxima edição comece a partir dela. Em seguida, envie o resumo descrito no início.

Paradas forçadas

Pare essa ação, termine tudo o que for seguro e relate o que parou e por quê. Nunca contorne uma parada.

  • Falhas de lint que você não consegue corrigir.
  • Um link ou imagem quebrados que você não consegue corrigir (ainda não 200 após implantar ou corrigir).
  • A leitura de retorno do teste falha e você não consegue encontrar a causa.
  • A filtragem de opt-out falha: a lista de opt-out não pode ser puxada ou construída, a consulta de audiência erra, ou um script recusa por causa de unsubs.txt. Nunca envie sem ela.
  • Erros do provedor acima do limite no meio do envio (blast.py sai com código 2 em provider.max_failures ou provider.max_failure_rate). Relate o erro; o envio é retomável uma vez corrigido.
  • Um envio que excederia a cota, uma atualização de plano ou qualquer outro gasto: pergunte ao usuário (regra do dinheiro).
  • Solicitações de login, 2FA ou reautenticação, CAPTCHAs, avisos da plataforma ou notificações de limite de taxa em uma ferramenta de postagem, formulários de pagamento ou faturamento.
  • Qualquer coisa que viole a lei de opt-out ou anti-spam (linha de cancelamento faltando, reassinando alguém que fez opt-out).
  • Uma afirmação que você não pode verificar. Descarte-a em vez de adivinhar.

Modo de revisão

Com autonomy.mode: review, os três portões também precisam da aprovação do usuário:

  1. Portão de rascunho. Mostre o assunto, o e-mail e a lista de itens no chat. Nada é enviado até que o usuário aprove a cópia.
  2. Portão de teste. Envie apenas para test_recipients. O usuário lê em uma caixa de entrada real e diz "vai" ou dá correções.
  3. Portão de envio. Mostre as contagens do dry run (enfileirados, excluídos, cancelados). Envie para todos apenas quando o usuário disser "sim" para aquele envio específico no chat. Um "sim" para uma etapa anterior não é um "sim" para esta.

Os posts sociais são mostrados antes de postar, e a lista de itens é proposta antes de escrever. Nunca passe uma flag de envio antes do portão correspondente.

Respondendo "quantos assinantes?"

Assinantes = usuários menos opt-outs. Conte os opt-outs da tabela de opt-out do usuário ou de unsubs.txt (no modo broadcast, execute broadcast_unsubs.py primeiro). Informe também a taxa de cancelamento da última edição.

Arquivos

  • config.example.yaml: cada valor específico da empresa, além de autonomy, provider.monthly_quota e social.post_via.
  • templates/email.html, templates/email.txt: o layout inicial.
  • scripts/: lint_email.py, send_test.py (com --readback), broadcast_sync.py, broadcast_create.py, broadcast_unsubs.py, blast.py, verify_delivery.py e build_audience.sql ou build_audience.py.
  • references/: voice-and-format.md, screenshots.md, sending.md, social.md, video.md.
  • O diretório de edições (issues_dir): uma pasta por edição nomeada NNN-YYYY-MM-DD-slug, cada uma contendo subject.txt, email.html, email.txt, audience.jsonl, unsubs.txt (se aplicável), screenshots (<issue>-<slug>.png), social.md, test_results.jsonl, NOTES.md e opcionalmente broadcast_id.txt.

Variáveis de ambiente

  • RESEND_API_KEY: chave de API do Resend.
  • UNSUB_SIGNING_SECRET: segredo para assinar links de cancelamento no modo de endpoint próprio (se usado).

Habilidades Relacionadas