O que gh-release faz?
Incrementa, changelog, tag, push, monitora.
Os comandos abaixo escrevem ~/.claude/skills/gh-release/scripts/ por extenso. Execute-os exatamente como escritos - mantenha o ~ inicial e não o expanda. Uma regra de permissão corresponde à string literal do comando, então /home/<você>/.claude/... (o til expandido), python3 ~/..., um caminho relativo, e um cd primeiro são cada um uma string diferente, e cada um pede permissão novamente. Um caminho com til não é "o caminho absoluto escrito informalmente" - para uma regra de permissão, ele é o caminho.
Duas coisas fazem as releases darem errado, e ambas acontecem antes da tag existir:
- Reinventar um bump que o repositório já automatiza. Uma edição manual mexe em arquivos que a própria tarefa do repositório teria tratado, perde os que ela conhece e pula sua verificação.
- Uma tag que não dispara nada. Parece exatamente com uma fila lenta de CI, e você descobre vinte minutos depois.
Os passos 1 e 3 existem para pegar esses casos.
0. Decidir a versão
Leia as tags (git tag --sort=-v:refname | head -5) para saber o formato do repositório (v1.2.3 vs 1.2.3) e a versão atual. Se o usuário nomeou uma versão, use-a. Caso contrário, proponha uma a partir dos commits desde a última tag - mudança radical é major, feat: é minor, caso contrário patch - e diga qual e porquê.
Recuse prosseguir em uma árvore suja, HEAD desanexado ou branch atrás do remoto. Liberar trabalho não commitado produz uma tag que ninguém consegue reproduzir.
1. Usar o próprio mecanismo de release do repositório
Sempre veja antes de fazer qualquer coisa manualmente:
~/.claude/skills/gh-release/scripts/versiontool.py discover
Ele relata habilidades do projeto, tarefas mise, scripts npm, alvos Make, receitas just, entradas scripts/-bin/ e configurações de ferramentas (cargo-release, bumpversion, release-please, git-cliff). Precedência:
kind=project-skill - pare de ler esta habilidade e siga aquela. É o próprio procedimento do repositório e ele sabe coisas que esta habilidade genérica não sabe.
Uma tarefa ou script (kind=mise-task|npm-script|make-target|just-recipe|script)
- leia-o antes de executá-lo, depois execute-o. Você precisa saber o que ele cobre para não duplicar ou pular trabalho. Tarefas típicas fazem algumas, mas não todas, de: bump, promoção de changelog, verificação, commit, tag, push. Anote quais, depois faça apenas o restante.
Muitos recebem a versão simples e adicionam o prefixo eles mesmos (mise run release 0.13.0 taggeando v0.13.0), então não passe uma tag onde uma versão é esperada. Se tiver --dry-run, use-o primeiro e mostre o plano ao usuário.
Uma configuração de ferramenta sem tarefa - use o próprio comando da ferramenta (cargo release <versão>, bump-my-version bump ...), não uma edição manual.
result=none - só então recorra ao passo 2.
2. Fallback: encontrar todos os lugares onde a versão mora
Apenas quando o passo 1 não encontrou nada.
~/.claude/skills/gh-release/scripts/versiontool.py locations <versão-atual>
Ele procura pela string literal da versão, não pela palavra "versão". Medido em um repositório real: uma busca pela chave version encontrou 5 arquivos, a string literal encontrou 8. As que faltaram soletravam a chave "version-name" (metadados GNOME) e "Version" (Plasma). Qualquer coisa que você perca envia um binário reportando a versão errada.
A saída é classificada: edit (mude), regenerate (lockfile - execute o comando da dica, nunca edite manualmente, ou --locked falha no CI), changelog (passo 4).
Depois verifique a versão anterior também - um acerto lá é um arquivo perdido na última release e desatualizado desde então. Corrija nesta.
3. Pré-verificação da tag
~/.claude/skills/gh-release/scripts/relwatch.py preflight <tag>
Ele lê .github/workflows/*.yml, extrai todos os padrões on.push.tags e informa se sua tag corresponde a algum e se aquele workflow parece criar uma release. result=NO_MATCH significa que enviar a tag não faz absolutamente nada.
Execute isso antes de commitar, enquanto mudar a tag é gratuito.
Também confirme visualmente que o passo de release do workflow usa a tag que você está prestes a enviar. Muitos workflows não verificam se a tag corresponde à versão no código, então uma incompatibilidade produz uma release cujos binários reportam a versão errada, silenciosamente e com CI verde.
4. Changelog
Se a tarefa do passo 1 promove o changelog sozinha, deixe-a e pule para o passo 5.
Mantenha um Changelog (há um cabeçalho ## [Unreleased]): promova-o.
## [Unreleased]torna-se## [X.Y.Z] - YYYY-MM-DD- adicione um novo
## [Unreleased]vazio acima - atualize as definições de link no final, incluindo a nova base do link de comparação
[Unreleased]
Sem changelog, ou sem seção Unreleased: escreva a entrada a partir dos commits desde a última tag, agrupados da mesma forma que o arquivo já os agrupa. Combine exatamente a voz existente - se as entradas são de uma linha, escreva de uma linha; se são prosa com leads em negrito, escreva assim.
De qualquer forma: descreva o que mudou para um usuário do projeto, não o que você fez no repositório.
Aplique a habilidade unslop a cada entrada. Um changelog é lido por anos, por pessoas decidindo se devem atualizar. "Várias melhorias e correções de bugs" é pior do que nenhuma entrada; o mesmo vale para uma entrada que repete o assunto do commit em palavras mais longas. As marcas específicas do documento estão listadas no passo 5 de docs-update/SKILL.md e se aplicam aqui inalteradas: sem rodeios, sem intensificadores vazios, sem hesitação onde a resposta é definitiva.
5. Verificar antes de tagear
~/.claude/skills/gh-release/scripts/versiontool.py verify <versão-antiga> # deve imprimir result=clean
Execute mesmo quando uma tarefa do repositório fez o bump. Um bumper escrito há seis meses não sabe sobre o arquivo que alguém adicionou na semana passada, e é exatamente assim que uma versão fica desatualizada em um canto da árvore. O histórico do changelog é ignorado; apenas arquivos editáveis contam.
Depois execute a verificação do projeto (build, teste, lint). Uma tag apontando para um commit vermelho tem que ser deletada e recriada, e deletar uma tag enviada é confuso para quem já a buscou.
6. Commit, tag, push
Pule o que a tarefa do passo 1 já fez. Se ela commitou, tagueou e enviou, vá direto para o passo 7.
Caso contrário: um commit para a release, assunto prefixado com o nome do branch conforme ~/.claude/CLAUDE.md. O bump e o changelog pertencem ao mesmo commit; eles são uma mudança.
git commit -m "[<branch>] chore(release): <versão>"
git tag -a <tag> -m "<tag>"
git push && git push origin <tag>
Envie o commit antes da tag. Uma tag que chega primeiro pode iniciar um build contra um commit que o remoto ainda não tem.
Anote o horário do push; ele limita o monitoramento.
7. Monitorar até a release existir
~/.claude/skills/gh-release/scripts/relwatch.py watch <tag> --timeout 1800
| Resultado | Significado |
|---|---|
released url=... | concluído |
ci_failed run=... conclusion=... | passo 8 |
no_run | nada foi disparado. A tag não correspondeu a nenhum padrão - execute preflight |
still_running | não é uma falha. Monitore novamente |
CI verde não é release: o passo de publicação pode ficar atrás do build, então o monitor continua esperando até que o objeto Release exista de fato.
Mesma regra de subagente que babysit-pr: um único monitor dentro de uma chamada Bash (--timeout 540) é mais barato inline; delegue apenas quando a espera abranger várias chamadas. Não pare antes da release existir ou você terá um bloqueador.
8. Quando o CI falha após a tag
A tag está errada, então retire-a em vez de contorná-la:
git push --delete origin <tag>
git tag -d <tag>
Corrija, depois recorte novamente a partir do passo 5 com o mesmo número de versão. Não incremente para pular uma falha: uma versão que ninguém nunca lançou não vale a pena queimar, e a lacuna convida alguém a procurar a release faltante.
Se a tag está pública há um tempo, ou existe uma release parcial, informe e deixe o usuário escolher entre deletá-la e enviar um patch por cima.
9. Relatório
Link PR/comparação, a tag, a URL da release, o que mudou e todos os arquivos incrementados. Se algo foi deixado para o usuário, nomeie-o.