Git Worklog (Registro de Trabajo Git)
Produce un registro de trabajo del proyecto (no un informe personal) leyendo los diffs reales de Git y el código circundante para cada día en un rango solicitado, luego escribe un archivo Markdown por día en .git-worklog/ y actualiza .git-worklog/index.md, preservando las notas humanas.
El trabajo determinista (cálculo de fechas, recolección de Git, cirugía de Markdown, integridad de la previsualización) lo realiza la CLI git-worklog y los scripts en scripts/. El trabajo de juicio (leer código, decidir qué cambió realmente, escribir el resumen) lo realizas tú y los subagentes por día. Nunca permitas que los mensajes de commit sustituyan la lectura del diff.
python3 y git deben estar disponibles; no es necesario instalar nada. Ejecuta la CLI como python3 -m git_worklog <comando> y cualquier script como python3 scripts/<nombre>.py, ambos desde este directorio. Cada uno imprime un objeto JSON en stdout. Salida 0 significa ok, 1 significa que se ejecutó y encontró un problema, 2 significa que no pudo ejecutarse.
0. Reglas de oro
- Sin parámetros → mostrar el menú y detenerse. No escanear Git, no generar subagentes, ni generar nada hasta que el usuario elija un rango.
- Leer código, no solo mensajes. Se debe leer el parche real de cada commit relevante y el contexto del código circundante. Ver
references/code-analysis-rules.md. Esto también aplica en modo informe: cuando un día no tiene registro de trabajo, sus mensajes de commit no son un sustituto: señala el vacío y pregunta. - Todo el proyecto, cada autor. El registro de trabajo siempre almacena a cada autor; nunca filtrar por
git config user.name/email. El modo informe puede filtrar por autor solo cuando el usuario nombra a la persona explícitamente — nunca inferir quién es "yo". - Máximo 30 días calendario para generación y rellenado. El límite acota el costo por subagente diario. El modo informe solo lee archivos de día existentes y no genera subagentes, por lo que lee hasta 90 días (
--max-days 90). De cualquier manera, si se supera el límite → rechazar, mostrar la cantidad de días solicitada, pedir al usuario que reduzca. Nunca truncar silenciosamente. - Dry-run primero, siempre. Cualquier solicitud válida produce solo una previsualización. Escribir solo después de que el usuario confirme explícitamente.
- Un archivo por día; el índice es navegación. Cada día es
.git-worklog/days/<fecha>.md; reanalizar un día nunca toca el archivo de otro día.index.mdse reconstruye a partir de los archivos de día. - Preservar la región MANUAL de cada día y la región MANUAL del índice, para siempre.
- Nunca ejecutar
git add/commit/push/fetch/pull/checkout/switch/merge/rebase.
1. Disparador y menú sin argumentos
Se activa con /git-worklog o solicitudes de registro de trabajo en lenguaje natural.
Cuando se invoca sin argumentos utilizables, imprime este menú textualmente y espera — no hacer nada más:
請選擇要整理的專案工作日誌範圍:
1. 今天
2. 指定日期
3. 最近 7 天
4. 最近 30 天
5. 自訂日期範圍
6. 今天,並包含尚未提交的異動
7. 自訂日期或範圍,並包含尚未提交的異動
日期範圍最多為 30 天。
所有操作都會先顯示 dry-run 預覽,不會直接修改專案檔案。
你可以直接輸入選項編號,或用自然語言回答,例如:
- 整理今天
- 整理 2026-07-01
- 整理最近 7 天
- 整理 2026-07-01 到 2026-07-10
- 整理今天並包含未提交異動
- 整理近 30 天
Los números de opción se asignan a: 1→hoy, 2→pedir una fecha, 3→days=7, 4→days=30, 5→pedir un rango desde/hasta, 6→hoy + include_uncommitted, 7→pedir una fecha/rango + include_uncommitted.
Manejo completo del menú, opciones y confirmación: references/interaction-flow.md.
1a. Ruta: generar o informar
Dos modos. Decidir antes de hacer cualquier otra cosa.
| El usuario quiere | Modo | Va a |
|---|---|---|
| El registro de trabajo en sí construido o completado — 「整理今天」「整理最近 7 天」「補 7/1 的日誌」 | Generar (escribe) | §2 en adelante |
| Una respuesta extraída del historial — 「整理上一週工作摘要」「整理 v1.0.1 CHANGELOG」「Daniel 上個月做了什麼」「目前有哪些技術債」 | Informe (solo lectura) | references/report-mode.md |
El indicador: el producto del modo de generar son archivos; el producto del modo de informar es prosa en la conversación. "整理今天" quiere un archivo de día. "整理上一週的工作摘要" quiere algo para pegar en una actualización de estado. Cuando sea realmente ambiguo, pregunta — no escribas archivos basándote en una suposición.
El modo informe lee los archivos de día existentes más Git, no escribe nada y, por lo tanto, no tiene puerta de dry-run o confirmación. Su único camino de escritura es rellenar un vacío, que devuelve a §§2–8 solo para esas fechas, con dry-run y confirmación incluidos.
El menú es solo para generar. El modo informe se alcanza mediante lenguaje natural o parámetros explícitos, nunca mediante un número de opción — el menú pregunta "qué rango construir", que no es la pregunta que responde el modo informe.
2. Normalizar entrada → parámetros canónicos
Tú (el modelo) conviertes el lenguaje natural en parámetros canónicos; los scripts nunca interpretan texto libre. Parámetros canónicos:
date · days · from · to · include_uncommitted, más los atajos 7d, 30d, y un YYYY-MM-DD simple.
- "整理今天" →
date=<hoy local> - "最近一週" →
days=7; "近一個月" →days=30(siempre 30, nunca la duración del mes) - "7 月 1 日到 7 月 10 日" →
from=2026-07-01 to=2026-07-10 - "包含未提交 / 連 working tree 一起" →
include_uncommitted=true
Los modos date / days / from+to son mutuamente excluyentes. Casos de normalización: references/date-parameter-contract.md.
2a. Resolver el idioma de salida (hoja de ruta §6.2)
Este es tu trabajo, no el de los scripts. Lo más alto del orden de prioridad vive solo en esta conversación: lo que pidió el usuario, el idioma en el que estás hablando, el idioma del host. Un script no puede ver nada de eso, y --language es cómo se lo dices. Resolver una vez por ejecución y pasar la misma etiqueta a todos lados.
Prioridad, de mayor a menor:
- Lo que el usuario pidió en esta solicitud — "用英文整理" →
en. Siempre gana. - El
languagedel proyecto en.git-worklog/config.json, si no esauto. Los scripts lo leen ellos mismos; pasa--language autoy déjalos hacerlo. - El idioma en el que estás conversando con este usuario, es decir, el idioma del host. Este es el caso normal y es una respuesta real — pásalo, con
--language-source agent-host.
Luego también pasa --language-source diciendo cuál de esos fue, para que el manifiesto registre por qué y no solo qué:
| Lo resolviste de | --language-source |
|---|---|
| El usuario pidiendo un idioma en esta solicitud | user-request |
| El idioma de esta conversación / tu host | agent-host |
| Nada que decir — deja que config y entorno decidan | omitir, con --language auto |
No dejes que el repositorio elija. Mensajes de commit en inglés, identificadores en inglés, comentarios en inglés y un README en inglés no deciden nada. Un repositorio completamente en inglés con una conversación en zh-TW produce un registro de trabajo en zh-TW. No "coincidas con el código base", y no leas este SKILL.md en inglés como una pista.
No inferir de la configuración regional del sistema operativo. Eres una ejecución alojada por un agente, y --language es exactamente el mecanismo que evita que un contenedor fijado en en_US anule a un usuario que habla chino. Los scripts no consultarán la configuración regional por ti (§6.2.5); eso es intencional, no un vacío que llenar.
Si el manifiesto de una ejecución devuelve source: "fallback" y una advertencia LANGUAGE_NOT_RESOLVED, no lograste pasar un idioma y la ejecución está a punto de escribirse en inglés. Vuelve a ejecutar con un --language explícito en lugar de aceptarlo (§6.2.14) — a menos que el inglés sea realmente correcto.
Los informes pueden diferir del registro de trabajo. Los archivos de día se escriben en el idioma de la ejecución que los produjo; un informe se escribe en el idioma de la solicitud que lo pide (§6.2.11). Leer archivos de día en zh-TW y producir una nota de lanzamiento en inglés es correcto y no necesita conversión de nada en disco.
Nunca traducir: rutas de archivo, símbolos de código, hashes de commit, nombres de API/clase/paquete, referencias de ramas e issues, o cualquier cosa en evidence[]. Explicar un término en el idioma de salida es bienvenido; renombrarlo no lo es.
3. Validar el rango de fechas (siempre primero)
python3 scripts/resolve_date_range.py <args> [--timezone <IANA>] [--today <YYYY-MM-DD>]
Pasa los parámetros canónicos, p. ej. --days 7, --date 2026-07-01, --from 2026-07-01 --to 2026-07-10, o un atajo como 7d. Agrega --include-uncommitted cuando se solicite.
- En
ok:false, informa el error al usuario y detente. Códigos comunes:TOO_MANY_DAYS(mostrarrequested_days, pedir que reduzca),ARG_CONFLICT,DAYS_OUT_OF_RANGE,INVALID_DATE,FROM_AFTER_TO,TO_WITHOUT_FROM. - En
ok:true, conservadates[](cada uno tienedate,start,endlímites semiabiertos),timezoneytimezone_source. Sitimezone_sourceessystem-offset(sin nombre IANA), dile al usuario qué desplazamiento se asumió y ofrece establecer uno.
Prioridad de zona horaria y regla de día semiabierto [00:00, próximo 00:00): references/date-parameter-contract.md.
4. Detectar estado del repositorio
python3 scripts/collect_git_history.py --repo <raíz> --info-only
NOT_A_GIT_REPO→ dile al usuario que este directorio no es un repositorio Git y detente.- Registra
root,branch(nulo sidetached_head),head/short_head,has_commits,dirty_worktree. Estos aparecen en el resumen de dry-run. - Repositorio vacío (
has_commits:false): coninclude_uncommitted=falseno hay nada que registrar — dilo. Coninclude_uncommitted=true, analiza solo el árbol de trabajo.
5. Análisis por día — un Subagente por Día
Dos comandos encierran esta sección. analyze prepare decide qué debe analizarse y en qué idioma; analyze collect decide si creer lo que se devolvió. Todo lo que hay entre ellos — leer los parches, entender el código, escribir la prosa — es tuyo y de los subagentes. La CLI nunca lo hace y no necesita una clave API de modelo.
5a. Preparar la ejecución (determinista, una vez para todo el rango):
python3 -m git_worklog analyze prepare --repo <raíz> \
--from <primera fecha> --to <última fecha> --timezone <tz> \
--language <etiqueta|auto> --language-source <fuente> \
--provider <proveedor> --model-json '<objeto modelo>' \
[--include-uncommitted]
Devuelve run_id, run_dir y tasks[] — una entrada por día calendario, cada una con un manifest_path (qué analizar) y un result_path (dónde debe escribirse su análisis). Consérvalo todo.
--language y --language-source provienen de §2a. Se resuelven una vez aquí y se estampan en cada manifiesto de la ejecución: el language.resolved de un manifiesto es contra lo que se verifica el resultado de cada día, y los días que discrepan bloquean toda la ejecución.
Resuelve <provider> y <model object> una vez para toda la ejecución con scripts/resolve_provider_model.py --host <anthropic|openai|google> (ver la tabla de modelos a continuación). model es un objeto — {display_name, model_id} más reasoning_effort solo para openai.
Cada manifiesto da file_groups (agrupados por área de trabajo real), required_context, analysis_rules, un flag large_day que recomienda Subagentes de Análisis de Código cuando el día es grande, parts_dir (donde van las partes de un fan-out — nunca junto al resultado del día, ver abajo), required_commit_file_pairs (§5b), y la autoría del día — authors[] (nombres distintos, orden de primera aparición) más commits[].author_name. Tú renderizas la línea 參與者 y cada entrada de 相關 commits desde estos directamente; el subagente nunca devuelve atribución.
El fan-out de un día grande escribe sus partes por grupo en parts_dir, no junto al result_path del día. results/ contiene las respuestas de la ejecución y collect falla la ejecución por cualquier archivo allí que no pidió (unknown) — entonces un fan-out que deriva un hermano de result_path bloquea el mismo día que se suponía que debía hacer tratable.
Los parches no están en el manifiesto — los subagentes los leen con git show.
5b. A qué se obliga cada día. Cada manifiesto lista required_commit_file_pairs: cada par (commit, archivo) que el día tocó, marcado como required o no. Obligatorio significa que el análisis del día debe dar cuenta de ese archivo — nombrarlo en el files[] de un elemento de trabajo es suficiente; una cita en evidence[] es más fuerte pero no exigida. Solo los archivos fuente son obligatorios; docs, config, CI, pruebas, binarios y archivos eliminados se listan pero están exentos (un archivo eliminado ya no está en el árbol de ese commit, por lo que no se puede citar).
Un archivo obligatorio que el análisis nunca menciona falla el día en §5d. Esto no es pedantería: un archivo que se cambió pero nunca se describió puede que nunca se haya leído, y eso es invisible en un resultado que de otro modo parece seguro.
5c. Genera un Subagente por Día por día, pasando su manifest_path y su result_path. El subagente debe leer los diffs reales y suficiente contexto de código, determinar el estado al final del día (una función agregada y luego revertida el mismo día no es un cambio en vivo), y escribir el JSON estructurado en references/subagent-contract.md en esa ruta, respondiendo solo DONE — los resultados nunca se devuelven como texto de respuesta, que los suelta y trunca (references/subagent-contract.md §6a). No debe escribir en el registro de trabajo. Los días sin commits aún escriben has_changes:false.
5d. Recoger el resultado de cada día (determinista), una vez que todos los subagentes terminan:
python3 -m git_worklog analyze collect --run-id <run_id> --repo <raíz>
Nada aquí nombra una fecha o un idioma: collect lee los propios manifiestos de la ejecución, por lo que un día no puede ser eliminado de la verificación al omitirse de una línea de comandos. Reporta:
complete/degraded/missing/invalid/unknown/failed_dates,results(fecha → objeto),partial_run,escalation_suggested_dates.- Una fecha en
missingoinvalides un día fallido, no uno vacío — nunca lo trates como "no pasó nada" y nunca recurras a sus mensajes de commit. unknownes un archivo de resultado que la ejecución nunca pidió. No lo fusiones.partial_run:truebloquea la aplicación por defecto (§9). Código de salida es1.
Tres cosas contra las que se verifica cada resultado, y cada una falla el día:
- Idioma — la etiqueta debe ser la que pidió su manifiesto.
- Precisión de la evidencia — cada entrada se verifica contra el árbol del commit que cita: el commit existe, el archivo existía en ese commit, el
symbolaparece en él, el rangolinesestá dentro de él. Un subagente que citamigrate_directorypara una función llamadaparse_legacyno te ha dicho nada que puedas seguir (#15). En un clon superficial, los commits inalcanzables reportanEVIDENCE_UNVERIFIABLEen lugar de fallar (#20); para subagentes, el equipo ha añadidopull_default_shallow: truea la configuración (ver $ROOT/references/skill-bootstrap.md) — pero esto no forma parte de la habilidad en sí y se analiza por separado. Suprimir advertencias decollectpara fechas donde el manifiesto ya sabía que los commits eran inalcanzables está en la hoja de ruta y actualmente no se admite. - Integridad requerida — los pares (commit, archivo) requeridos no mencionados en ningún elemento de trabajo fallan el día.
5e. Reintento y escalada. Si la recolección reporta fallas, no reconstruyas la ejecución desde cero — vuelve a lanzar solo los días que fallaron, pasando su result_path original. Consulta references/retry-and-escalation.md.
6. Previsualización Dry-Run
python3 scripts/dry_run.py \
--run-id <run_id> --repo <raíz> \
--timezone <tz> --language <etiqueta> --language-source <fuente>
Esto produce un resumen de dry-run completo:
- Rango de fechas (cada fecha con su
start/end, zona horaria, número de commits). - Resumen de autores (distintos, sin duplicados).
- Resumen de archivos (fuente vs. no fuente con recuentos).
[DRY-RUN]en el título.- Para cada fecha de la
collect: daily_stats (commits, archivos, adiciones, eliminaciones), work_items (solo resumen de 2 líneas, sin WorkItem completo),dry_review_needed(si lo reporta cualquier día). partial_runcon un banner cuando sea verdadero.- Días sin cambios: mostrar una línea, no eliminarlos.
dry_annotation: truepara días que fallaron la recolección.- Sin información sobre evidencia de commit (aún).
total_statscon recuentos generales para todo el rango.
Advertencia sobre dry-run: el estado de la evidencia es preliminar; la evidencia no se verifica completamente aquí. La verificación completa ocurre en collect, y algunos días marcados como dry_annotation: true pueden verse bien después del reintento.
7. Confirmación del usuario
Después de que se muestre la previsualización de dry-run, espera confirmación explícita. En la confirmación:
- Pregunta "¿Confirmas que se escriban estos archivos?" con una [lista numerada de archivos que se escribirán].
- Si el usuario dice que sí, pasa a §8.
- Si el usuario dice que no, informa: "Operación cancelada. No se escribieron archivos." y detente.
- Si el usuario pide cambios, como lenguaje, zona horaria o rango, regresa al paso apropiado (§2, §2a o §4).
- Si la confirmación incluye modificaciones solicitadas, repite el dry-run y luego la confirmación.
8. Escribir los archivos de registro de trabajo
python3 scripts/write_worklogs.py \
--run-id <run_id> --repo <raíz> \
--timezone <tz> --language <etiqueta> --language-source <fuente>
Esto escribe/actualiza .git-worklog/days/<fecha>.md para cada día y reconstruye .git-worklog/index.md. Cada archivo de día tiene una región MANUAL protegida (ver formato de marcador).Nunca reemplazar el contenido anterior con la última ejecución — solo fusionar:
- Si el archivo de día ya existe: reemplazar la sección
AUTOMATEDdesde la primera ocurrencia de<!-- AUTOMATED -->hasta la próxima<!-- MANUALo fin de archivo, dejando intacto elMANUALy todo lo anterior. Si el archivo termina con<!-- MANUAL_START -->, agrega la región después de ella. - Si el archivo no existe: crearlo con el contenido completo, incluyendo el marcador
<!-- MANUAL_START -->vacío.
index.md se reconstruye completamente desde los archivos de día en .git-worklog/days/. Conserva cualquier sección MANUAL que comience desde <!-- MANUAL --> en adelante; todo lo demás se reemplaza.
Región MANUAL protegida en archivos de día:
Cada archivo de día debe tener:
<!-- MANUAL_START -->
<!-- MANUAL_END -->
El contenido entre estos marcadores nunca es tocado por las escrituras automatizadas. Si existe contenido manual anterior, se preserva.
9. Modo parche / aplicar por defecto
Cuando una ejecución tiene collected.partial_run como true, bloquear la aplicación por defecto (escribir archivos) a menos que el usuario la solicite explícitamente. En la previsualización de dry-run, agregar un banner:
⚠️ Atención: Ejecución parcial — algunos días no se completaron. Escribir ahora
dejaría esos días como no analizados o faltantes. Se requiere confirmación
explícita ("aplicar de todas formas").
10. Ejecuto completamente el flujo de trabajo (no cambios aquí)
(Toda la sección original §10 permanece sin cambios en la salida traducida.)
Referencias
references/code-analysis-rules.md— Cómo leer y analizar el código.references/interaction-flow.md— Flujo completo de interacción con el usuario.references/report-mode.md— Modo de solo lectura.references/date-parameter-contract.md— Contrato de parámetros de fecha.references/subagent-contract.md— Contrato del subagente.references/retry-and-escalation.md— Reintentos y escalada.