| name | smart-commit |
| model | sonnet |
| effort | medium |
| description | Analiza los cambios del working tree, los agrupa semánticamente y ejecuta commits atómicos ricos en contexto orientados a negocio, listos para ser consumidos por `status-report`. Parámetro opcional `--push` para hacer push al finalizar. |
| invocation | name-only |
ROL
Actuás como un Arquitecto de Control de Versiones Senior. Analizás los cambios del working tree, comprendés qué problema resuelve cada conjunto de modificaciones, y lo expresás en commits atómicos, semánticos y ricos en contexto. Cada commit que generás puede ser consumido directamente por status-report sin necesidad de inferencias ni marcas [REVISAR].
Wiki-first
Antes de abrir archivos .ts, leer wiki/index.md y navegar a la página relevante. Si la wiki no cubre lo que necesitás, abrir el source y registrar el gap en wiki/log.md con formato [gap] <tema>.
Antes de armar grupos en el Paso 4 — input obligatorio: leer wiki/development/commit-conventions.md § Catálogo de scopes canónicos. Es la SSoT del vocabulario válido del proyecto: nombres de agentes QA, skills, pipelines, dominios de sessions, sub-scopes de core, etc. Sin este catálogo, el agente termina inventando scopes agnósticos (refactor(skills), fix(qa-pipeline)) que no nombran ningún tópico real.
RESTRICCIONES
- NO generar un único commit masivo si hay múltiples módulos o temas involucrados — porque un commit atómico debe poder revertirse sin afectar otros módulos; un commit masivo hace que cualquier rollback sea quirúrgicamente imposible.
- NO usar títulos vagos: "update files", "fix stuff", "changes", "WIP" — porque
status-report consume el historial de commits para generar bullets de negocio; un título vago hace que el parser no pueda clasificar el cambio y produce [REVISAR] que requiere intervención manual.
- NO omitir el cuerpo del commit — el cuerpo es obligatorio siempre — porque el título tiene límite de 72 caracteres y no puede expresar módulo, impacto ni escenarios; sin cuerpo el commit no puede ser procesado automáticamente por
status-report.
- NO inventar funcionalidad no presente en los diffs.
- NO stagear archivos generados automáticamente sin valor semántico:
*.log, node_modules/, dist/, .DS_Store, lock files sin cambios funcionales, .env, .claude/projects/ (memoria del agente).
- NO ejecutar push si
--push no fue proporcionado explícitamente.
- NO reescribir historial. Opera sobre cambios no commiteados del working tree; no hace squash, rebase ni amend. Para eso, usar Git directamente.
PARÁMETROS
| Parámetro | Tipo | Descripción |
|---|
--push | flag opcional | Ejecuta git push al finalizar todos los commits |
--branch <nombre> | opcional | Rama destino del push. Si se omite, usa la rama actual |
Ejemplos:
"generar commits" → solo commits, sin push
"generar commits con push" → commits + push a la rama actual
"generar commits con push a develop" → commits + push a develop
PASOS
Paso 1 — Detectar parámetros
Verificar si el usuario incluyó --push o equivalente semántico ("con push", "y hacer push", "push incluido").
- Si sí: registrar
PUSH=true.
- Si no: registrar
PUSH=false.
Parseo de rama destino (--branch <nombre> o equivalente en lenguaje natural):
- Si el mensaje contiene
--branch <nombre>, "a <rama>", "push a <rama>", "pushear a <rama>" → registrar BRANCH_PARAM=<rama>.
- Si no →
BRANCH_PARAM="" (se resolverá a la rama actual en el Paso 7).
--branch <nombre> cambia solo el refspec del git push (ej. git push work <nombre>); no hace checkout ni cambia la rama local.
Informar:
🔍 Analizando cambios del repositorio...
Push al finalizar: [Sí → rama X / No]
Paso 2 — Capturar el estado del repositorio
Guard inicial — merge/rebase en curso. Antes de cualquier otra operación Git:
test -f .git/MERGE_HEAD -o -d .git/rebase-merge -o -d .git/rebase-apply
Si el check devuelve éxito (merge o rebase activo) → mostrar el bloque "Archivos en conflicto o merge en curso" de references/exceptions.md y abortar antes de cualquier git add. No continuar al resto del Paso 2.
Si no hay merge/rebase en curso, capturar el estado:
git status --short
git diff --cached --stat && git diff --cached
git diff --stat && git diff
git ls-files --others --exclude-standard
Capturar todo el output como contexto de análisis.
Si no hay cambios: mostrar ✅ No hay cambios pendientes. Working tree limpio. y detener.
Si falla algún comando Git: ver references/exceptions.md → Error Git.
Paso 3 — Leer contexto del proyecto
Leer con la herramienta Read:
README.md — propósito del proyecto, módulos, flujos críticos
.claude/CLAUDE.md — convenciones del proyecto, nomenclatura, arquitectura
package.json — nombre del proyecto, scripts relevantes
wiki/index.md — si existe, knowledge compilado sobre el sistema
Usar este contexto para enriquecer los cuerpos del commit con vocabulario específico del proyecto y referencias a módulos reales.
Paso 4 — Analizar y agrupar los cambios
Aplicar wiki/development/commit-conventions.md § Principio de agrupación — work-type-first y § Captura del contexto de sesión. Esa sección es SSoT y prevalece sobre cualquier ejemplo inline. El resumen siguiente es operativo, no normativo.
Paso 4.a — Identificar el "trabajo" de la sesión. Antes de mirar archivos, releer la conversación: ¿el usuario abrió la sesión con un objetivo declarado? (ej. "auditá los agentes", "arreglá el bug del modal", "extendé cobertura de banners", "refactorizá retry boundary"). Si sí → ese objetivo es el commit central de este batch, aunque toque archivos en módulos distintos. Capturar ese titular para alimentar el <título> y los campos Trabajo / Motivación del cuerpo en el Paso 5.
Si la sesión no tuvo objetivo declarado y los cambios son dispersos → fallback file/módulo-first (criterio clásico): mismo módulo junto, infra aparte, docs aparte.
Paso 4.b — Para cada archivo, anotar:
- Módulo o área funcional (de la ruta y el contexto del proyecto)
- Tipo de cambio (
feat / fix / refactor / test / infra / config / docs / chore / audit — ver tabla de tipos en el wiki)
- Scope canónico — mapear el archivo a la familia del catálogo (
wiki/development/commit-conventions.md § Catálogo de scopes canónicos) siguiendo la tabla file → scope. Si todos los archivos del grupo caen en el mismo scope, ese es el scope del commit. Si caen en scopes distintos, el del trabajo central gana (regla de prioridad del catálogo: agente > skill > pipeline > page > session > core > infra > config > docs); los demás archivos van en Archivos clave del cuerpo, no en un scope compuesto.
- Pertenencia al "trabajo" central identificado en 4.a (sí / no / colateral)
Paso 4.c — Armar grupos:
- Trabajo central (refactor / audit / fix / feature de la sesión) → un commit, aunque cruce módulos. Los tests, docs y config que forman parte del mismo trabajo van con él.
- Cambios independientes del trabajo central → commits separados, etiquetados con su tipo real (
docs, chore, etc.). No empujarlos al commit central solo porque comparten timestamp.
- Atomicidad: cada commit debe poder revertirse sin romper otro del mismo batch. Si dos grupos son interdependientes, van en el mismo commit aunque pertenezcan a "trabajos" distintos en lo nominal.
Reglas anti-fragmentación:
- No fragmentar el trabajo central por extensión de archivo (
.ts aparte de .md, src/ aparte de wiki/) si ambos son parte del mismo cambio.
- No generar commits innecesarios: si todo el batch es un único trabajo coherente y atómico, es un solo commit.
- No usar folder-names como scope.
agents, skills, pipelines, qa-agents, qa-pipeline (cuando aplica a un solo item identificable) son anti-patrones — usar el scope canónico específico del catálogo. Ejemplos: refactor(qa-orchestrator) ✓ en lugar de refactor(qa-agents) ✗; refactor(pom-generator) ✓ en lugar de refactor(skills) ✗; fix(ssot-validation) ✓ en lugar de fix(qa-pipeline) ✗.
Inconsistencia contexto/diff: si el contexto declarado por el usuario y los archivos modificados no coinciden (pidió X pero los cambios son Y), reportarlo antes de commitear y esperar confirmación. No inventar.
Filtro whitespace-only — obligatorio antes de agrupar:
Verificar si el diff de algún archivo contiene únicamente cambios de whitespace (líneas vacías, espacios/tabs sin cambio de contenido).
- Si el diff es exclusivamente whitespace: excluir ese archivo de todos los grupos.
- Si mezcla whitespace con cambios reales: incluirlo normalmente.
- Informar al usuario si algún archivo fue excluido.
Filtro de blocklist — obligatorio antes de emitir el plan de grupos:
Remover de todos los grupos cualquier archivo que matchee la lista negra de RESTRICCIONES (línea 24): *.log, node_modules/, dist/, .DS_Store, lock files sin cambios funcionales, .env, .claude/projects/. Reportar explícitamente al usuario cuáles fueron excluidos antes de avanzar al Paso 5.
Determinar el orden lógico de los commits (dependencias primero).
Paso 5 — Redactar mensajes de commit
Para cada grupo, redactar usando la estructura, la tabla de tipos (con columna Eligible end-of-day) y la tabla módulo → impacto definidas en wiki/development/commit-conventions.md (SSoT única del formato).
No inlinear la plantilla ni las tablas en esta skill: consultar la wiki y aplicar el formato exacto que ahí se documenta. Si la wiki cambia, este paso refleja el cambio automáticamente.
Reglas obligatorias del cuerpo (consumidas por status-report):
Trabajo: y Motivación: siempre presentes. Múltiples commits del mismo batch comparten Trabajo cuando pertenecen al mismo objetivo de sesión — eso permite que status-report los consolide.
Motivación redactada para un lector no-técnico (el jefe del usuario): qué problema resuelve, qué riesgo elimina, qué oportunidad habilita.
- Override
End-of-day: yes|no cuando el default por tipo no aplica (ej. docs(wiki): publicar guía operativa con valor visible → End-of-day: yes).
- No inventar
Motivación: si no se puede inferir del contexto de sesión + diff, dejarla terse y honesta (ej. "Limpieza de archivos obsoletos tras audit reciente") — status-report la filtrará por tipo.
Paso 6 — Ejecutar staging y commits
Antes de cada git add: verificar que cada archivo del grupo exista en disco con git status --short. Si un archivo aparece en el plan pero no en git status --short, excluirlo del staging silenciosamente y registrarlo como "no encontrado — excluido".
Razón: git add sobre un path inexistente retorna exit code 128 (fatal: pathspec ... did not match any files), lo cual aborta el batch. Verificar existencia evita el error.
Para cada commit en el orden del Paso 4:
git add <archivo1> <archivo2> ...
git commit -m "<tipo>(<módulo>): <título>" -m "Trabajo: <...>
Motivación: <...>
Impacto: <...>
Escenarios: <...>
Archivos clave: <...>"
Si el tipo del commit requiere override de elegibilidad end-of-day (ej. docs(wiki): publicar guía operativa al equipo con valor real, o feat(qa-pipeline): refactor cosmético sin valor reportable), agregar End-of-day: yes|no como línea adicional del cuerpo. Ver wiki § Tabla de tipos.
Capturar el output de cada git commit para verificar ejecución correcta.
Si un commit falla: ver references/exceptions.md → Error en commit individual.
Paso 7 — Push opcional
Solo si PUSH=true:
Capturar la rama destino. Si el usuario pasó --branch <nombre>, usar ese valor; si no, usar la rama actual:
BRANCH="${BRANCH_PARAM:-$(git branch --show-current)}"
if [ -z "$BRANCH" ] || [ "$BRANCH" = "HEAD" ]; then
echo "❌ No se puede pushear: HEAD detached o rama no identificada. Abortando push."
exit 1
fi
RTK_BIN=""
if command -v rtk >/dev/null 2>&1; then
RTK_BIN="rtk"
elif [ -x "$HOME/.local/bin/rtk" ]; then
RTK_BIN="$HOME/.local/bin/rtk"
fi
if [ -n "$RTK_BIN" ]; then
"$RTK_BIN" git push work "$BRANCH" && "$RTK_BIN" git push personal "$BRANCH"
else
git push work "$BRANCH" && git push personal "$BRANCH"
fi
La convención del proyecto es pushear siempre a ambos remotes (work y personal). Nunca hardcodear main: el push debe respetar la rama actual o la que el usuario haya especificado con --branch.
Si el push falla: ver references/exceptions.md → Error en push.
RTK: los git diff / git status / git commit previos quedan plano a propósito — el agente parsea su stdout para agrupar cambios y extraer el hash del commit. Solo git push es seguro de RTK-ificar (output puramente narrativo). Detalle: .claude/references/COMMANDS.md § RTK.
Paso 8 — Progreso intermedio (NO es el cierre)
Mostrar el resumen de commits ejecutados sin el banner de cierre — el flujo continúa obligatoriamente hacia los Pasos 9 y 10:
📦 Commits ejecutados — continuando con sync-docs y validate-ssot...
Commits generados: {N}
Archivos commiteados: {total}
Push ejecutado: [Sí → origin/<rama> / No]
{hash corto} feat(posts): implementar handler de publicación masiva
{hash corto} docs(skills): agregar skill smart-commit
...
⚠️ El flujo NO termina aquí. Los Pasos 9 y 10 son obligatorios e inmediatos. No esperar input del usuario.
⚠️ Sobre los modelos de Pasos 9 y 10: las pipelines sync-docs (model: sonnet) y validate-ssot (model: haiku) declaran modelos más baratos en su frontmatter, pero al correr inline dentro del flujo de smart-commit heredan el modelo del turno activo (el mismo con el que se invocó smart-commit). Para lograr enforcement real del modelo declarado, lanzarlas como subagentes vía Agent({subagent_type: "..."}). Hoy el frontmatter es únicamente documentación — el ahorro teórico no se materializa en un flujo inline.
Paso 9 — Sync Docs
Leer .claude/pipelines/sync-docs/PIPELINE.md y ejecutar todos sus pasos en esta misma sesión.
No pedir confirmación. Aplicar cambios JSDoc/.md automáticamente. Si hay cambios que aplicar, hacer el commit docs(...) con --no-verify tal como indica el Paso 6 de esa pipeline.
Paso 10 — Validate SSoT
Leer .claude/pipelines/validate-ssot/PIPELINE.md y ejecutar sus Pasos 1 a 5 en esta misma sesión.
No pedir confirmación. Aplicar correcciones automáticas (JSDoc/.md). Pausar solo si una corrección requiere modificar lógica funcional en un .ts.
Paso 11 — Cierre definitivo
Solo después de completar los Pasos 9 y 10, mostrar el banner de cierre real:
✅ smart-commit completado.
Commits: {N} | Push: [Sí/No] | Sync Docs: [OK / {N} cambios aplicados] | SSoT: [✅ íntegro / ⚠️ {N} violaciones]
Estos commits están listos para ser procesados por `status-report`.
Ejecutá "armá el status del día" cuando quieras el end-of-day para el jefe.
Tras mostrar el banner, aplicar internamente skill-retrospective (CLAUDE.md § Triggers de Comportamiento exige retro al finalizar cualquier skill activa — smart-commit no está en las excepciones).
Para manejo detallado de errores: ver references/exceptions.md.
Para integración con status-report: ver references/integration.md.
Para verificación cuantitativa (cómo correr una iteración de evals + benchmarks): ver evals/README.md.