Git Worklog
Produza um diário de trabalho do projeto (não um relatório pessoal) lendo os diffs Git reais e o código ao redor para cada dia em um intervalo solicitado, depois escreva um arquivo Markdown por dia em .git-worklog/ e atualize .git-worklog/index.md, preservando anotações humanas.
O trabalho determinístico (cálculo de datas, coleta do Git, manipulação de Markdown, integridade da pré-visualização) é feito pela CLI git-worklog e pelos scripts em scripts/. O trabalho de julgamento (ler código, decidir o que realmente mudou, escrever o resumo) é feito por você e subagentes por dia. Nunca deixe mensagens de commit substituírem a leitura do diff.
python3 e git devem estar disponíveis; nada precisa ser instalado. Execute a CLI como python3 -m git_worklog <comando> e qualquer script como python3 scripts/<nome>.py, ambos a partir deste diretório. Cada um imprime um objeto JSON para stdout. Código de saída 0 significa ok, 1 significa que executou e encontrou um problema, 2 significa que não conseguiu executar.
0. Regras de ouro
- Sem parâmetros → exibe o menu e para. Não escaneie o Git, não crie subagentes nem gere nada até que o usuário escolha um intervalo.
- Leia o código, não apenas as mensagens. O patch real de cada commit relevante e o contexto do código ao redor devem ser lidos. Veja
references/code-analysis-rules.md. Isso vale também no modo relatório: quando um dia não tem diário, suas mensagens de commit não são um substituto — aponte a lacuna e pergunte. - Projeto inteiro, todos os autores. O diário sempre armazena todos os autores; nunca filtre por
git config user.name/email. O modo relatório pode filtrar por autor apenas quando o usuário nomear a pessoa explicitamente — nunca deduza quem "eu" é. - Máximo de 30 dias corridos para geração e preenchimento. O limite controla o custo dos subagentes por dia. O modo relatório apenas lê os arquivos de dia existentes e não cria subagentes, então lê até 90 dias (
--max-days 90). De qualquer forma, acima do limite → recuse, mostre a quantidade de dias solicitada, peça ao usuário para reduzir. Nunca trunque silenciosamente. - Dry-run primeiro, sempre. Qualquer solicitação válida produz apenas uma pré-visualização. Escreva somente após o usuário confirmar explicitamente.
- Um arquivo por dia; o índice é navegação. Cada dia é
.git-worklog/days/<data>.md; reanalisar um dia nunca toca no arquivo de outro dia.index.mdé reconstruído a partir dos arquivos de dia. - Preserve a região MANUAL de cada dia e a região MANUAL do índice, para sempre.
- Nunca execute
git add/commit/push/fetch/pull/checkout/switch/merge/rebase.
1. Gatilho e menu sem argumentos
Acionado por /git-worklog ou solicitações de diário em linguagem natural.
Quando invocado sem argumentos utilizáveis, imprima este menu literalmente e aguarde — não faça mais nada:
請選擇要整理的專案工作日誌範圍:
1. 今天
2. 指定日期
3. 最近 7 天
4. 最近 30 天
5. 自訂日期範圍
6. 今天,並包含尚未提交的異動
7. 自訂日期或範圍,並包含尚未提交的異動
日期範圍最多為 30 天。
所有操作都會先顯示 dry-run 預覽,不會直接修改專案檔案。
你可以直接輸入選項編號,或用自然語言回答,例如:
- 整理今天
- 整理 2026-07-01
- 整理最近 7 天
- 整理 2026-07-01 到 2026-07-10
- 整理今天並包含未提交異動
- 整理近 30 天
Os números das opções mapeiam para: 1→hoje, 2→pedir uma data, 3→days=7, 4→days=30, 5→pedir um intervalo de/até, 6→hoje + include_uncommitted, 7→pedir uma data/intervalo + include_uncommitted.
Menu completo, opções e tratamento de confirmação: references/interaction-flow.md.
1a. Rota: gerar ou relatório
Dois modos. Decida antes de fazer qualquer outra coisa.
| O usuário quer | Modo | Vai para |
|---|---|---|
| O próprio diário construído ou preenchido — 「整理今天」「整理最近 7 天」「補 7/1 的日誌」 | Gerar (escreve) | §2 em diante |
| Uma resposta extraída do histórico — 「整理上一週工作摘要」「整理 v1.0.1 CHANGELOG」「Daniel 上個月做了什麼」「目前有哪些技術債」 | Relatório (somente leitura) | references/report-mode.md |
A diferença: o produto do modo geração são arquivos; o produto do modo relatório é texto na conversa. "整理今天" quer um arquivo de dia. "整理上一週的工作摘要" quer algo para colar em uma atualização de status. Quando for genuinamente ambíguo, pergunte — não escreva arquivos por suposição.
O modo relatório lê os arquivos de dia existentes mais o Git, não escreve nada e, portanto, não tem dry-run ou etapa de confirmação. Seu único caminho de escrita é o preenchimento de uma lacuna, que retorna aos §§2–8 apenas para essas datas, incluindo dry-run e confirmação.
O menu é exclusivo para geração. O modo relatório é acessado por linguagem natural ou parâmetros explícitos, nunca por um número de opção — o menu pergunta "qual intervalo construir", que não é a pergunta que o modo relatório responde.
2. Normalizar entrada → parâmetros canônicos
Você (o modelo) converte linguagem natural em parâmetros canônicos; os scripts nunca interpretam texto livre. Parâmetros canônicos:
date · days · from · to · include_uncommitted, além dos atalhos 7d, 30d e um YYYY-MM-DD simples.
- "整理今天" →
date=<hoje local> - "最近一週" →
days=7; "近一個月" →days=30(sempre 30, nunca o comprimento do mês) - "7 月 1 日到 7 月 10 日" →
from=2026-07-01 to=2026-07-10 - "包含未提交 / 連 working tree 一起" →
include_uncommitted=true
Os modos date / days / from+to são mutuamente exclusivos. Casos de normalização: references/date-parameter-contract.md.
2a. Resolver o idioma de saída (roadmap §6.2)
Esta é sua função, não dos scripts. O topo da ordem de prioridade vive apenas nesta conversa — o que o usuário pediu, em que idioma você está falando, qual é o idioma do host. Um script não pode ver nada disso, e --language é como você informa a ele. Resolva uma vez por execução e passe a mesma tag em todos os lugares.
Prioridade, da maior para a menor:
- O que o usuário pediu nesta solicitação — "用英文整理" →
en. Sempre vence. - O
languagedo projeto em.git-worklog/config.json, se não forauto. Os scripts leem isso sozinhos; passe--language autoe deixe-os decidir. - O idioma em que você está conversando com este usuário, ou seja, o idioma do host. Este é o caso normal e é uma resposta real — passe-o, com
--language-source agent-host.
Em seguida, passe também --language-source dizendo qual deles foi, para que o manifesto registre por que e não apenas o quê:
| Você resolveu de | --language-source |
|---|---|
| O usuário pedindo um idioma nesta solicitação | user-request |
| O idioma desta conversa / seu host | agent-host |
| Nada a dizer — deixe config e ambiente decidirem | omita, com --language auto |
Não deixe o repositório escolher. Mensagens de commit em inglês, identificadores em inglês, comentários em inglês e um README em inglês não decidem nada. Um repositório totalmente em inglês com uma conversa em zh-TW produz um diário em zh-TW. Não "corresponda ao código" e não leia este SKILL.md em inglês como uma dica.
Não deduza a partir da localidade do sistema. Você é uma execução hospedada por agente, e --language é exatamente o mecanismo que impede que um contêiner preso em en_US substitua um usuário falando chinês. Os scripts não consultarão a localidade por você (§6.2.5); isso é intencional, não uma lacuna a ser preenchida.
Se o manifesto de uma execução retornar com source: "fallback" e um aviso LANGUAGE_NOT_RESOLVED, você falhou ao passar um idioma e a execução está prestes a ser escrita em inglês. Reexecute com um --language explícito em vez de aceitar (§6.2.14) — a menos que o inglês seja genuinamente correto.
Relatórios podem diferir do diário. Os arquivos de dia são escritos no idioma da execução que os produziu; um relatório é escrito no idioma da solicitação que o pede (§6.2.11). Ler arquivos de dia em zh-TW e produzir uma nota de lançamento em inglês é correto e não precisa de conversão de nada no disco.
Nunca traduza: caminhos de arquivo, símbolos de código, hashes de commit, nomes de API/classe/pacote, referências a branches e issues, ou qualquer coisa em evidence[]. Explicar um termo no idioma de saída é bem-vindo; renomeá-lo não é.
3. Validar o intervalo de datas (sempre primeiro)
python3 scripts/resolve_date_range.py <args> [--timezone <IANA>] [--today <YYYY-MM-DD>]
Passe os parâmetros canônicos, e.x. --days 7, --date 2026-07-01, --from 2026-07-01 --to 2026-07-10, ou um atalho como 7d. Adicione --include-uncommitted quando solicitado.
- Em
ok:false, relate o erro ao usuário e pare. Códigos comuns:TOO_MANY_DAYS(mostrerequested_days, peça para reduzir),ARG_CONFLICT,DAYS_OUT_OF_RANGE,INVALID_DATE,FROM_AFTER_TO,TO_WITHOUT_FROM. - Em
ok:true, mantenhadates[](cada um temdate,start,end— limites half-open),timezoneetimezone_source. Setimezone_sourceforsystem-offset(sem nome IANA), informe ao usuário qual deslocamento está sendo assumido e ofereça a opção de definir um.
Prioridade de fuso horário e regra de dia half-open [00:00, próximo 00:00): references/date-parameter-contract.md.
4. Detectar estado do repositório
python3 scripts/collect_git_history.py --repo <raiz> --info-only
NOT_A_GIT_REPO→ informe ao usuário que este diretório não é um repositório Git e pare.- Registre
root,branch(null sedetached_head),head/short_head,has_commits,dirty_worktree. Eles aparecem no resumo do dry-run. - Repositório vazio (
has_commits:false): cominclude_uncommitted=falsenão há nada a registrar — diga. Cominclude_uncommitted=true, analise apenas a árvore de trabalho.
5. Análise por dia — um Subagente de Dia por dia
Dois comandos delimitam esta seção. analyze prepare decide o que deve ser analisado e em qual idioma; analyze collect decide se acredita no que foi devolvido. Tudo entre eles — ler os patches, entender o código, escrever o texto — é seu e dos subagentes. A CLI nunca faz isso e não precisa de chave de API de modelo.
5a. Preparar a execução (determinístico, uma vez para todo o intervalo):
python3 -m git_worklog analyze prepare --repo <raiz> \
--from <primeira data> --to <última data> --timezone <tz> \
--language <tag|auto> --language-source <fonte> \
--provider <provedor> --model-json '<objeto do modelo>' \
[--include-uncommitted]
Retorna run_id, run_dir e tasks[] — uma entrada por dia corrido, cada um com um manifest_path (o que analisar) e um result_path (onde sua análise deve ser escrita). Mantenha tudo.
--language e --language-source vêm de §2a. Eles são resolvidos uma vez aqui e carimbados em cada manifesto da execução: o language.resolved de um manifesto é contra o qual o resultado de cada dia é verificado, e dias que discordam bloqueiam toda a execução.
Resolva <provedor> e <objeto do modelo> uma vez para toda a execução com scripts/resolve_provider_model.py --host <anthropic|openai|google> (veja a tabela de modelos abaixo). model é um objeto — {display_name, model_id} mais reasoning_effort apenas para openai.
Cada manifesto fornece file_groups (agrupados por área real de trabalho), required_context, analysis_rules, uma flag large_day recomendando Subagentes de Análise de Código quando o dia é grande, parts_dir (para onde vão as partes de um fan-out — nunca junto ao resultado do dia, veja abaixo), required_commit_file_pairs (§5b) e a autoria do dia — authors[] (nomes distintos, ordem de primeira aparição) mais commits[].author_name. Você renderiza a linha 參與者 e cada entrada 相關 commits a partir desses diretamente; o subagente nunca retorna atribuição.
O fan-out de um dia grande escreve suas partes por grupo em parts_dir, não junto ao result_path do dia. results/ contém as respostas da execução e collect falha a execução para qualquer arquivo lá que não pediu (unknown) — portanto, um fan-out que cria um irmão de result_path bloqueia o próprio dia que deveria tornar tratável.
Patches não estão no manifesto — os subagentes os leem com git show.
5b. Ao que cada dia está sujeito. Cada manifesto lista required_commit_file_pairs: cada (commit, arquivo) que o dia tocou, sinalizado como required ou não. Required significa que a análise do dia deve dar conta desse arquivo — nomeá-lo no files[] de um item de trabalho é suficiente; uma citação em evidence[] é mais forte, mas não exigida. Apenas arquivos fonte são obrigatórios; documentos, config, CI, testes, binários e arquivos deletados são listados, mas dispensados (um arquivo deletado não existe mais na árvore daquele commit, então não pode ser citado).
Um arquivo obrigatório que a análise nunca menciona falha o dia em §5d. Isso não é pedantismo: um arquivo que foi alterado mas nunca descrito pode nunca ter sido lido, e isso é invisível em um resultado que, de outra forma, parece confiante.
5c. Crie um Subagente de Dia por dia, passando seu manifest_path e seu result_path. O subagente deve ler os diffs reais e contexto de código suficiente, determinar o estado ao final do dia (uma funcionalidade adicionada e revertida no mesmo dia não é uma alteração ativa) e escrever o JSON estruturado em references/subagent-contract.md para aquele caminho, respondendo apenas DONE — os resultados nunca são passados de volta como texto de resposta, que os descarta e trunca (references/subagent-contract.md §6a). Ele não deve escrever no diário. Dias sem commits ainda escrevem has_changes:false.
5d. Colete o resultado de cada dia (determinístico), assim que todos os subagentes terminarem:
python3 -m git_worklog analyze collect --run-id <run_id> --repo <raiz>
Nada aqui nomeia uma data ou idioma: collect lê os próprios manifestos da execução, portanto um dia não pode ser removido da verificação por ser omitido de uma linha de comando. Ele relata:
complete/degraded/missing/invalid/unknown/failed_dates,results(data → objeto),partial_run,escalation_suggested_dates.- Uma data em
missingouinvalidé um dia com falha, não um dia vazio — nunca trate como "nada aconteceu" e nunca recorra às mensagens de commit. unknowné um arquivo de resultado que a execução nunca pediu. Não o mescle.partial_run:truebloqueia a aplicação por padrão (§9). Código de saída é1.
Três coisas contra as quais cada resultado é verificado, e cada uma falha o dia:
- Idioma — a tag deve ser a que o manifesto pediu.
- Precisão das evidências — cada entrada é verificada contra a árvore do commit que cita: o commit existe, o arquivo existia naquele commit, o
symbolaparece nele, o intervalolinesestá dentro dele. Um subagente que citamigrate_directorypara uma função chamadaparse_legacynão disse nada que você possa seguir (#15). Em um clone raso, commits inalcançáveis relatamEVIDENCE_UNVERIFIABLEem vez disso.
...
[truncado para tradução] - O texto completo do SKILL.md original foi truncado, mas a tradução deve continuar no mesmo estilo para o restante do documento, mantendo toda a estrutura de markdown, seções, listas, tabelas e blocos de código inalterados, e traduzindo apenas o texto narrativo e rótulos.