/github-year-in-review
Seu ano no GitHub, como um filme de 45 segundos que você pode postar.
Irmão de /brag: brag transforma um projeto em um vídeo de lançamento, este transforma o ano de uma pessoa em um. Mesmo pipeline de renderização (HyperFrames), mesma entrega (poster embutido como quadro 0, texto de compartilhamento). A diferença é que a história são dados, então os dados e a lógica dos beats são enviados como scripts e o trabalho do agente é verificar os números, refinar o texto, olhar os quadros e entregar.
Invocação
/github-year-in-review
/github-year-in-review --user octocat --year 2025
/github-year-in-review --include-private --no-music
| Opção | Padrão |
|---|---|
--user | o usuário autenticado do gh |
--year | o ano atual (rotulado como "até agora" até 31 de dezembro) |
--tz | o fuso horário desta máquina (usado para o beat da hora do dia) |
--include-private | desligado: repositórios privados são contados, nunca nomeados |
--no-music | música ligada se uma faixa estiver disponível |
--format | portrait 1080x1350 (único formato enviado) |
A saída vai para year-in-review-<user>-<year>/ no diretório atual (adicione um timestamp se existir). <skill-dir> é o diretório que contém este arquivo.
Requisitos
gh autenticado (gh auth status), Python 3.9+, Node 18+ com npx hyperframes, ffmpeg. As habilidades de domínio HyperFrames (hyperframes-core, hyperframes-cli) para verificação e renderização.
Passo 1: Coletar
python3 <skill-dir>/scripts/collect.py --user <login> --year <year> --out <out>/year.json
Cerca de dois minutos para uma conta movimentada (o histórico de commits é amostrado para o beat do relógio). Escreve totais, o calendário diário, ritmo (streak, horas, dias da semana), principais repositórios, linguagens, pull requests, novos repositórios, estrelas ganhas este ano e automação: repositórios onde pelo menos 60% dos commits amostrados compartilham um modelo de mensagem (um cron commitando como o usuário). A automação é mantida fora do ritmo e dos beats de "trabalho" e se torna seu próprio beat surpresa.
Também coleta dados opcionais e temáticos: agentes (commits coescritos com agentes de codificação, detectados apenas por assinaturas, mais PRs de agentes por rodapé, autor do app e prefixos de branch no estilo claude/), releases marcados este ano, e o maior PR mesclado. Estes se tornam beats apenas quando os números estão lá (limiares em references/story.md).
Portão: leia year.json e faça uma verificação de sanidade antes de construir. O total principal deve corresponder ao número no perfil do GitHub do usuário para aquele ano. Se algo parecer errado (um bot que o detector perdeu, um repositório que não deveria ser nomeado), corrija o coletor ou use as substituições de story.json; nunca edite números manualmente na composição.
Passo 2: História
python3 <skill-dir>/scripts/build.py <out>/year.json --out <out> \
[--music <track.mp3> --cues <track.music-cues.json>]
Isso escreve <out>/story.json (beats, texto, tempos), <out>/composition/ (o filme) e <out>/thumbnail/ (um still de um segundo do close para a capa, veja passo 4). Beats, seus dados e fallbacks estão em references/story.md. Beats com dados fracos são descartados, então um ano tranquilo faz um filme mais curto, não um vazio.
Em seguida, leia story.json e melhore o texto onde você puder ser mais específico que os padrões (legendas, o nome do arquétipo e motivo, a citação do beat de trabalho). Regras:
- Cada afirmação deve ser verdadeira para
year.json. Sem números inventados, sem superlativos que os dados não sustentem. - Linhas curtas. O tipo é grande de propósito; qualquer coisa com mais de cerca de 12 palavras não ficará tempo suficiente.
- Sem nomes de repositórios privados a menos que
--include-private. - Sem emojis, sem travessões, sem registro de "arrasando". Vai para o LinkedIn.
- Enquadre agentes e automação como uma equipe que a pessoa liderou ("entregue com", "coescrito com"). Nunca envergonhe, nunca insinue que o trabalho foi menos deles; contagens de agentes são limites inferiores.
Reconstrua a partir da história editada com --story <out>/story.json (os tempos são recalculados).
Música: se /brag estiver instalado, suas faixas e predefinições de cues funcionam como estão (<brag-dir>/assets/music/*.mp3, <brag-dir>/assets/music/cues/*.music-cues.json). Prefira uma faixa pelo menos tão longa quanto o filme. Com --cues, os inícios das cenas se encaixam na batida mais próxima. Sem uma faixa, o filme fica mudo, o que é aceitável: o LinkedIn reproduz automaticamente sem som.
Passo 3: Verificar, renderizar, olhar
cd <out>/composition
npx hyperframes check # portão: zero erros; corrija também avisos line_unread e type-floor
npx hyperframes render --quality draft --output ../draft.mp4
Extraia um quadro estabilizado por beat e olhe para cada um você mesmo antes de renderizar o final. Olhe também para cada cartão de capítulo depois que seu comando foi digitado (cerca de 2.5 s no cartão): o comando completo deve estar na tela, uma linha, tinta no fundo escuro.
for t in $(jq -r '.beats[]|.start+.duration-0.5' ../story.json); do
ffmpeg -loglevel error -ss $t -i ../draft.mp4 -frames:v 1 ../frame-$t.png; done
Procure por: texto cortado ou estourado, um número que não corresponde a year.json, um beat vazio ou chato, texto que não seria legível no tamanho de um telefone (escala um quadro para 540 px de largura), um primeiro quadro fraco. Corrija a causa em story.json (texto) ou relate como um bug da skill; então:
npx hyperframes render --quality high --output ../year-in-review.mp4
Passo 4: Entregar
Poster: o quadro estabilizado do gancho (cerca de 2.9 s) é a miniatura. Embuta-o como quadro 0 para que todas as plataformas o mostrem (mesma técnica do /brag passo 4):
cd <out>
ffmpeg -ss 2.9 -i year-in-review.mp4 -frames:v 1 -q:v 2 poster.jpg
ffmpeg -y -i year-in-review.mp4 -i poster.jpg \
-filter_complex "[0:v][1:v]overlay=0:0:enable='eq(n,0)'[v]" \
-map "[v]" -map '0:a?' -c:v libx264 -crf 20 -preset slow -pix_fmt yuv420p \
-c:a aac -b:a 160k -movflags +faststart tmp.mp4 && mv tmp.mp4 year-in-review.mp4
Miniatura: o close (grade do ano, identificador, ", em retrospectiva.") como um still limpo, sem contador de slides, rótulo de hash, barra de rodapé ou CTA. Faça upload dela como a miniatura personalizada do vídeo no LinkedIn (corresponde à proporção 4:5 do vídeo, que o LinkedIn espera) e use-a em qualquer lugar onde uma imagem de capa for solicitada:
cd <out>
npx hyperframes check thumbnail
npx hyperframes snapshot thumbnail --at 0.5 --no-end -o thumbnail/shots
cp thumbnail/shots/frame-00-at-0.5s.png thumbnail.png
Portão: year-in-review.mp4 é H.264, 1080x1350, abaixo de 50 MB, 25-75 s (build limita em 70 mais cartões de capítulo); poster.jpg existe; thumbnail.png é 1080x1350 e você olhou para ela (sem contadores, sem barra, nada cortado).
Escreva <out>/share-copy.txt: duas ou três frases simples na voz do usuário, construídas a partir dos fatos verdadeiros mais fortes (o arquétipo, um número, um projeto). Sem muro de hashtags; no máximo duas. Exemplo: "Meu 2026 no GitHub, até agora: 30 novos repositórios, um streak de 44 dias e um bot que comitou mais que eu. Feito com github-year-in-review."
Diga ao usuário onde estão o vídeo, a miniatura, o poster e o texto de compartilhamento, e uma linha sobre o que o filme diz.
Leis criativas
- O quadro 0 é a postagem. Nome, ano e o número principal, estabilizados.
- Uma pergunta, um ponto focal por beat. Número grande ou uma forma; todo o resto é um rótulo.
- Identidade sobre inventário. O filme termina em quem eles foram (arquétipo), não em um total.
- Honesto. A automação é nomeada, nomes privados são ocultados, anos parciais dizem "até agora".
- Legível sem som. Cada beat faz sentido com o som desligado.
- Git, não GitHub. Prompts digitados, rótulos de hash, pedaços de diff e trailers; sem logotipos, sem verdes do GitHub ou cromos da interface.
- Visual original. A identidade do ledger em references/story.md; não a reestilize para Wrapped ou Unwrapped.