O que transcribe-summarize faz?
Áudio de entrada, uma transcrição de saída e, opcionalmente, um conjunto de atas de reunião. O caminho padrão executa inteiramente na máquina do usuário.
Duas coisas tornam isso diferente de chamar o Whisper você mesmo, e ambas surgiram de um dia de medição, não de design:
- O Whisper inventa fala sobre silêncio, e um modelo maior não ajuda. Em
uma chamada real com 40 s de silêncio de entrada, o
large-v3produziu um segmento de 18 segundos de uma palavra repetida 55 vezes. Esta habilidade filtra esses segmentos e os mantém, com as métricas que os rejeitaram, em um arquivo auxiliar para que a decisão seja auditável. - Limpar o áudio supera a escolha do modelo. Normalizar e cortar silêncio
reduziu os segmentos inventados de 2 para 0 e corrigiu uma palavra que tanto
large-v3quantoturboerraram. Está ativado por padrão.
Configuração
ffmpeg e ffprobe devem estar no PATH — no macOS brew install ffmpeg, no Windows
winget install Gyan.FFmpeg, no Linux apt install ffmpeg.
Todo o resto é stdlib. O backend traz sua própria biblioteca, e apenas a
selecionada, então escolha com uv run --with:
| backend | plataforma | especificação --with |
|---|---|---|
mlx-whisper — padrão no Apple Silicon | macOS arm64 apenas | 'mlx-whisper>=0.4.2' |
faster-whisper — padrão em outros lugares | mac / Windows / Linux | 'faster-whisper>=1.2' |
parakeet — opcional | Apple Silicon verificado | 'parakeet-mlx' |
groq, openai, elevenlabs, gemini — opcionais, rede | qualquer | nada para instalar |
Se a biblioteca estiver faltando, o erro exibe o comando exato. Não adivinhe.
Executando
Declare o helper no topo de todo bloco de comando — o estado do shell não persiste entre chamadas de ferramenta:
ts() {
UV="$(command -v uv || ls "$HOME/.local/bin/uv" "$HOME/.cargo/bin/uv" \
/opt/homebrew/bin/uv /usr/local/bin/uv 2>/dev/null | head -1)"
"$UV" run --with "$1" --script "$HOME/.claude/skills/transcribe-summarize/scripts/transcribe.py" "${@:2}"
}
# Apple Silicon
ts 'mlx-whisper>=0.4.2' meeting.m4a
# Windows / Linux
ts 'faster-whisper>=1.2' meeting.m4a --backend faster-whisper
# Viés do decodificador para jargões conhecidos e corrige um nome que ele sempre erra
ts 'mlx-whisper>=0.4.2' meeting.m4a --prompt 'Terragrunt, EKS' --replace 'north wind=Northwind'
Use o caminho absoluto. Um caminho relativo só resolve se o diretório de trabalho atual for o diretório da habilidade.
Contrato de saída
<dir_saida>/
<stem>.md a transcrição, com âncoras [hh:mm:ss]
<stem>-artifacts/
<stem>.srt legendas
<stem>.json cada segmento, incluindo os suprimidos
<stem>.run.json backend, modelo, deslocamentos de corte, contagem da guarda
--json imprime esses caminhos para stdout como JSON. Relate caminhos absolutos ao usuário;
um arquivo que ele tenha que caçar não é uma entrega.
Os carimbos de data/hora seguem o relógio da gravação original. O corte encurta o áudio
durante a decodificação, e os deslocamentos são mapeados de volta antes que qualquer coisa seja
escrita, para que o .srt se alinhe com o próprio arquivo do usuário.
A regra de rede — declare-a, depois obedeça-a
Um backend de rede é acessível apenas quando o usuário o solicita naquela
invocação. Nunca como fallback, nunca após um backend local falhar, nunca porque
seria mais rápido. --backend auto não pode alcançar um; não há caminho de código.
Antes de qualquer coisa ser enviada, a ferramenta imprime provedor, endpoint, tamanho do arquivo, duração
e custo estimado, então aguarda. Use --dry-run para mostrar ao usuário esse bloco
antes de confirmar. Em uma sessão não interativa, um upload não confirmado é recusado.
As chaves vêm do ambiente, uma variável por backend, e de nenhum outro lugar. Nunca aceite uma como flag, nunca ecoe uma, nunca escreva uma em um arquivo.
| backend | chave | modelo | $/hora | diariza |
|---|---|---|---|---|
groq | GROQ_API_KEY | whisper-large-v3-turbo | 0.04 | não |
groq | GROQ_API_KEY | whisper-large-v3 (padrão) | 0.111 | não |
elevenlabs | ELEVENLABS_API_KEY | scribe_v2 | 0.22 | até 32 |
gemini | GEMINI_API_KEY | gemini-3.5-transcribe | 0.306 | até 3 |
openai | OPENAI_API_KEY | whisper-1 | 0.36 | não |
--backend gemini — as duas coisas a dizer antes de executá-lo
ts '' /caminho/para/audio.m4a --backend gemini --dry-run # mostra o bloco, não envia nada
ts '' /caminho/para/audio.m4a --backend gemini # então executa
Nada para instalar — é stdlib http.client, então o argumento --with é
vazio. Dois fatos pertencem à frase que você diz ao usuário antes de executá-lo,
porque nenhum é visível na linha de comando:
- O áudio é enviado duas vezes. O Gemini não tem endpoint de etapa única: o arquivo vai primeiro para a API de Arquivos do Google, e a solicitação de transcrição então carrega apenas o URI que retornou. O Google mantém esse upload por 48 horas. O bloco de divulgação imprime isso; não pule por cima dele.
- 30 minutos é o limite máximo, não a hora que a própria página do Google anuncia. A hora se aplica apenas sem carimbos de data/hora de palavras ou diarização, e este backend sempre solicita ambos — sem deslocamentos de palavras não há relógio para mapear de volta ao arquivo do usuário. Uma gravação mais longa é recusada antes do upload começar.
Não ofereça o modo smart do Gemini. Não está conectado, de propósito. Se o
usuário perguntar por ele — é o recurso principal do modelo, e ele remove palavras de
enchimento e reescreve autocorreções faladas — a resposta é que a API do Google recusa
carimbos de data/hora de palavras e rótulos de orador junto com ele, então não produziria
nenhum .srt e nenhum orador, e ele muda as palavras. A remoção de enchimento acontece na
etapa de notas, onde é rotulada como um resumo e verificada. Veja
references/backends.md.
A guarda de qualidade
Ativada por padrão. Segmentos suprimidos permanecem no .json com o motivo e as
métricas; eles são removidos do .md e .srt. --guard mark os mantém inline
sinalizados, --guard off o desabilita.
Não se transfere para todos os backends. As regras fortes leem as métricas do
decodificador do Whisper. faster-whisper, Groq e OpenAI retornam todos os três, então a guarda é o
mesmo código. Parakeet, ElevenLabs e Gemini não retornam nenhum deles e caem
apenas para as regras independentes de backend — a ferramenta informa isso em tempo de execução. Veja
references/backends.md.
Se o usuário perguntar por que um trecho da transcrição está faltando, leia o .json: a
resposta está lá com os números que o causaram.
Começando a partir de uma transcrição que você já possui
A maioria das reuniões já é transcrita pela plataforma, e muitas vezes não há áudio
nenhum. Teams e Zoom fornecem um .vtt (às vezes .srt), e ele é
ilegível como prosa: uma legenda a cada poucos segundos, frases cortadas entre legendas, o
nome do orador repetido em cada linha, códigos de tempo por toda parte.
Esse é um ponto de entrada suportado. Nada é re-transcrito — o caminho do áudio é pulado completamente:
"$HOME/.claude/skills/transcribe-summarize/scripts/normalise_transcript.py" meeting.vtt
# -> meeting.md, legendas reagrupadas em parágrafos, oradores atribuídos, uma âncora por parágrafo
Em seguida, prossiga exatamente como se a transcrição tivesse sido decodificada aqui: leia-a, peça
os fatos da reunião e escreva as notas em references/notes-register.md.
--no-speakers remove a atribuição se os rótulos de origem estiverem errados ou indesejados.
É uma conversão de formato e nada mais. Nenhuma palavra é alterada, nenhum enchimento removido, nenhuma gramática corrigida. Decidir o que foi dito é a etapa de sumarização e ela tem suas próprias regras. Se um usuário lhe entregar uma transcrição bagunçada e pedir para "arrumá-la", normalize o formato aqui e faça o julgamento nas notas — não reescreva silenciosamente as palavras de alguém em um documento que deveria registrá-las.
Os oradores são mantidos na transcrição e proibidos nas notas, o que não é uma
contradição: uma transcrição é um artefato de trabalho e pode carregar proveniência; as
notas são um registro e não podem. notes_check.py ainda rejeitará um rótulo
Speaker 2 bruto nas notas.
Se alguém passar um .vtt para transcribe.py, ele para e aponta para aqui em vez de
tentar decodificá-lo.
Arquivos de vídeo
.mp4 é o que um download do Teams ou Zoom realmente é, e funciona diretamente — não
há necessidade de extrair o áudio primeiro. Verificado como funcionando: .mp4, .mov, .mkv,
.webm, além de todos os contêineres de áudio (.m4a, .mp3, .wav, .flac, .opus).
o ffmpeg extrai a faixa de áudio; o vídeo é ignorado e nunca enviado.
Um arquivo sem faixa de áudio — uma gravação de tela silenciada — é recusado de imediato, antes que qualquer backend de rede o receba. Essa verificação é executada antes da porta de saída especificamente para que um vídeo silencioso nunca seja enviado e faturado.
Revisão é uma etapa, não um extra opcional
A saída da transcrição é um rascunho. Diga isso e faça o usuário verificá-la.
A transcrição automática erra com confiança de maneiras que nenhum limite detecta. Medido
em áudio real neste projeto: o large-v3 silenciosamente descartou a correção falada de um
número por um orador, e todo backend ouviu "board pack" como "board packs up". Ambas
leem perfeitamente fluentes. A guarda de qualidade captura invenções sobre silêncio; ela não
pode capturar um erro de audição plausível, e você também não pode lendo a saída.
Portanto, o fluxo de trabalho é transcrever → o usuário verifica → então notas:
- O
.mdda transcrição termina com uma seção "Vale a pena verificar" — carimbos de data/hora classificados onde uma escuta provavelmente mais compensará (segmentos de menor confiança, qualquer coisa contendo números). Aponte o usuário para ela explicitamente. - Nomes, números e datas são o que verificar. Eles são a primeira coisa a se degradar e os mais caros de errar em um registro.
- As correções vão para o
.md, manualmente ou com--replaceem uma nova execução. Em seguida, regere qualquer coisa construída a partir dele.
Nunca apresente uma transcrição ou um conjunto de notas como verificado. Você não ouviu o áudio; o usuário ouviu. Diga o que foi decodificado, diga onde é menos certo e deixe-o confirmar.
Editando e regenerando
O .md é a fonte. Edite-o e reconstrua o PDF — sem re-transcrição:
"$HOME/.claude/skills/transcribe-summarize/scripts/notes_check.py" notes.md
"$HOME/.claude/skills/transcribe-summarize/scripts/render_pdf.py" notes.md
Execute o verificador novamente após qualquer edição. A edição manual é exatamente quando um vazamento de proveniência ou uma linha inferida de "próximos passos" é introduzida.
Escrevendo as notas
Quando o usuário quiser atas de reunião em vez de uma transcrição, você as escreve —
leia a transcrição e produza o documento você mesmo. Existe um fallback
scripts/summarize.py que chama um modelo de rede, mas é para executar este pipeline
fora de uma sessão do Claude Code; dentro de uma, é um upload inútil.
Pergunte primeiro — três coisas que o áudio não pode lhe dizer
Quase nenhum backend aqui identifica oradores. Todo mecanismo Whisper e o Parakeet
não retornam nenhum campo de orador. Duas exceções: --backend elevenlabs (Scribe)
diariza até 32 oradores, e --backend gemini até 3. Ambos retornam
rótulos posicionais em vez de nomes — speaker_0 e spk:0 respectivamente, os formatos
medidos a partir de respostas ao vivo em 2026-09-04 e 2026-09-06 — e o
registro proíbe um rótulo bruto em um documento de notas, em qualquer formato. Então eles lhe dizem
quantas pessoas falaram e quais linhas pertencem juntas; eles ainda não podem lhe dizer
quem. A atribuição vem do usuário de qualquer maneira; a diarização apenas torna o
mapeamento possível a partir da transcrição em vez da memória.
Antes de escrever notas, pergunte:
- Quem estava presente. Sem nomes, escreva as notas sem nenhuma atribuição — impessoal, "foi afirmado que…". Nunca invente um nome, um cargo ou um rótulo posicional. Se a transcrição tornar óbvio quem falou (alguém é chamado pelo nome), você pode atribuir isso; ambiguidade significa sem nome.
- A data da reunião. A data de hoje é um padrão, não um fato. O áudio é frequentemente redigido dias após a conversa, e uma data errada em um registro factual é pior do que nenhuma data. Confirme-a.
- O que foi a reunião — um título nos termos dos próprios participantes.
Pergunte todos os três em uma única mensagem, não um de cada vez, e ofereça a data de hoje como padrão para que o usuário só tenha que corrigi-la. Se o usuário se recusar a fornecer participantes, prossiga sem atribuição e diga que foi isso que você fez.
Antes de escrever uma única linha, leia references/notes-register.md. É curto
e é toda a especificação. Não é um conselho de estilo; as regras nele foram
aprendidas ao ter seções deletadas manualmente de um documento real, e as razões
são legais em vez de estéticas.
As duas regras que ele ativa:
- Apenas resumo factual. O que foi dito. Sem análise, sem implicações, sem "próximos passos", sem "o que não foi coberto", sem preencher uma lacuna.
- Lê-se como um relato de protocolo por alguém que estava lá. Nunca menciona
uma gravação, uma transcrição, áudio, um modelo ou qualquer artefato de decodificador — sem
códigos de tempo, sem rótulos
Speaker 2.
Em seguida, verifique-o, toda vez — o registro não é autoaplicável e um modelo solicitado a resumir adicionará análise sem ser solicitado:
"$HOME/.claude/skills/transcribe-summarize/scripts/notes_check.py" notes.md
Saída 0 está limpo; saída 1 lista arquivo:linha para cada violação. Corrija-as antes de
entregar o documento. Execute-o também no PDF — um vazamento que só existe no arquivo
renderizado ainda conta.
Orientação é bem-vinda, mas após as notas e fora do documento. Ofereça sua leitura em conversa, ou escreva-a em um arquivo separado. Nunca a anexe.
O PDF
"$HOME/.claude/skills/transcribe-summarize/scripts/render_pdf.py" notes.md
Chrome headless, Chromium ou Edge, descobertos automaticamente. Se nenhum estiver instalado, ele escreve o HTML, informa e sai com 0 — o HTML ainda é uma entrega.
Proveniência
A decodificação local é mlx-whisper (MLX) ou faster-whisper (CTranslate2); a preparação
de áudio é ffmpeg. Os backends de rede chamam os endpoints de transcrição do Groq e da
OpenAI diretamente sobre stdlib urllib — sem SDK de fornecedor.
Manter a proveniência fora de um documento de notas muda o que o documento diz, não o que aconteceu. Gravar uma chamada sem consentimento é uma ofensa criminal em muitas jurisdições. Se o usuário pedir garantias que você não pode dar, não as invente.
Referências
references/backends.md— especificação completa do backend, formato de resposta, métricas disponíveisreferences/notes-register.md— regras para escrever atas de reunião factuaisreferences/privacy.md— modelo de privacidade e perguntas frequentes
Histórico de versões
- 2026-09-04 — suporte ao backend Gemini adicionado; modo
smartbloqueado de propósito - 2026-08-20 — normalizador de transcrição
.vtt - 2026-08-13 — guarda de qualidade, pipeline de revisão