Finance Audit — Informe CFO Personal
Convierte una carpeta de archivos de estados de cuenta sin procesar en un Informe CFO Personal: datos verificados más una capa narrativa que responde ¿Qué pasó? ¿Por qué? ¿Qué debería hacer a continuación?
Precisión ante todo: los montos se leen textualmente y se concilian contra el saldo corriente; no se inventa nada.
Independiente de bancos. Funciona con cualquier exportación de banco o cuenta, siempre que tenga una lista de transacciones. Las columnas, filas de encabezado y el orden de fechas (DMY/MDY/YMD) se detectan automáticamente por archivo; el limpiador de comerciantes/contrapartes es independiente del rail (UPI, POS, ACH, SEPA, tarjeta, transferencia, …). Nada está codificado para un banco específico: tú confirmas la asignación detectada automáticamente y ajustas las palabras clave de categoría.
Pipeline (5 etapas)
ingest -> parse -> categorize (bucle hasta >=99%) -> analyze -> report (servir + recarga en caliente)
Los scripts están en este skill. Ejecútalos contra la carpeta de auditoría del usuario (la carpeta que contiene los archivos de estados de cuenta). Establece dos variables primero:
SKILL="<ruta absoluta a este directorio del skill>" # la carpeta que contiene este SKILL.md
ROOT="<ruta absoluta a la carpeta de auditoría>" # donde están los archivos de estado de cuenta
Privacidad — nunca confirmar datos reales
Todos los archivos de estados de cuenta, saldos, narraciones y salidas generadas permanecen locales en ROOT/. El repositorio del skill solo incluye plantillas, configuración de ejemplo y fixtures ficticios (assets/fixtures/sample_analysis.json).
Ignorados por Git (nunca subir): output/ (incluyendo report.html, analysis.json, audit.db), archivos de estados de cuenta y config/mapping.json / anulaciones activas.
Etiquetas opcionales en config/mapping.json: account_label o account_last4 para el pie de página de la barra lateral (por defecto "Cuenta principal"). Nombre comercial en config/business.json → display_name (por defecto "Negocio").
Asume que los archivos de estados de cuenta ya están descargados en ROOT (PDF / XLSX / XLS / CSV / TXT).
Elige el runtime (el usuario prefiere Node.js):
- Usar Node cuando
nodeesté disponible Y ninguna entrada sea un PDF. - Usar Python cuando alguna entrada sea un PDF (la ruta de Node no puede parsear PDF) o
nodeno esté disponible.
Detectar e instalar dependencias:
# Ruta Node (preferida)
command -v node && node --version # necesita Node >= 22 para sqlite integrado
( cd "$ROOT" && npm install xlsx ) # SOLO para .xls/.xlsx; CSV/TXT no necesitan nada
# Ruta Python (alternativa / requerida para PDF)
python3 --version
pip install openpyxl "xlrd==2.0.1" pdfplumber pandas # + pandas para la etapa analyze
Define cómo invocarás una etapa ($STAGE = ingest|parse|categorize|analyze|report):
# Node: node "$SKILL/scripts/node/$STAGE.mjs" --root "$ROOT" [args]
# Python: python3 "$SKILL/scripts/python/$STAGE.py" --root "$ROOT" [args]
Paso 1 — Ingestión y detección
node "$SKILL/scripts/node/ingest.mjs" --root "$ROOT" # o python3 .../ingest.py --root "$ROOT"
Esto muestra una vista previa de cada archivo y escribe config/mapping.json con una fila de encabezado, roles de columna y un date_format explícito detectados automáticamente. Lee la vista previa y verifica mapping.json: los bancos difieren. Si una entrada tiene un _date_note, el orden de fechas era ambiguo (por ejemplo, 03/04/2024); confirma date_format con el usuario. Cada entrada de archivo necesita: header_row, data_start_row, date_format (un patrón strptime como %d/%m/%Y, o auto), columns (rol → índice basado en 0), y amount_mode:
debit_credit— columnas separadas de retiro + depósito (más común)signed— una columnaamountcuyo signo indica direcciónamount_type— una columnaamountmás una columnatypeque contiene DR/CR
Corrige cualquier índice incorrecto antes de parsear.
Paso 2 — Parseo, normalización, deduplicación, validación
node "$SKILL/scripts/node/parse.mjs" --root "$ROOT" # o .../parse.py
Escribe output/audit.db (SQLite). La división débito/crédito se deriva del monto con signo para que siempre coincida con la cadena de saldo (manejando correctamente los reembolsos codificados como retiros negativos). Requiere que la verificación de integridad PASE (o n/a cuando no hay columna de saldo). Si FALLA:
- Vuelve a verificar las columnas de
mapping.json/data_start_row/date_format. - Vuelve a leer la vista previa de salida estándar de ingest (vuelve a ejecutar ingest si es necesario); confirma que no incluiste filas de encabezado/pie de página.
- Por archivo,
chain_issues > 0señala las filas exactas que se malinterpretaron.
No continúes a la categorización hasta que el parseo esté reconciliado.
Paso 3 — Categorizar (bucle hasta >= 99% por valor)
cp "$SKILL/config/categories.example.json" "$ROOT/config/categories.json" # solo primera ejecución
# Para una cuenta de negocio/freelancer, también:
cp "$SKILL/config/business.example.json" "$ROOT/config/business.json" # luego edítalo
node "$SKILL/scripts/node/categorize.mjs" --root "$ROOT" # o .../categorize.py
Precedencia de reglas: overrides.json > business.json > categories.json; gana la priority más alta. La categorización es primero el script; llega al 99% así:
- Ejecuta categorize. Lee el resumen de cobertura y
output/uncategorized.csv(comerciantes agrupados, valor más grande primero). - Para comerciantes cuya identidad es obvia por la narración, añade reglas a
config/overrides.jsontú mismo (ver formato abajo) — no hace falta preguntar. - Para comerciantes ambiguos (no está claro quién o qué, o personal vs. negocio), haz al usuario una pregunta concisa, luego añade la regla.
- Vuelve a ejecutar categorize. Repite hasta que la cobertura de valor ≥ 99%.
Formato de config/overrides.json:
{ "rules": [
{ "keywords": ["ACME", "ACME CORP"], "primary": "Income", "sub": "Acme retainer", "when": "credit" },
{ "keywords": ["BIGRENT"], "primary": "Housing", "sub": "Rent", "is_business": 0 }
] }
Apunta a que cada transacción tenga un primary_cat y sub_cat. El respaldo factual de contraparte P2P etiqueta las transferencias pero cuenta como "necesita revisión" — convierte las importantes en reglas reales.
Paso 4 — Analizar (crea output/analysis.json)
python3 "$SKILL/scripts/python/analyze.py" --root "$ROOT"
Calcula segmentos por año fiscal, informes de categoría, narrativa de CFO, motor de ingresos, resumen de gastos, áreas problemáticas y análisis post-mortem de negocio a partir de output/audit.db. Escribe output/analysis.json (y opcionalmente findings.md localmente — nunca confirmar).
Requiere pandas. Ajusta config/business.json → display_name para la etiqueta de la sección de negocio (por defecto "Negocio").
Paso 5 — Generar el informe (servir + recarga en caliente + abrir automáticamente)
python3 "$SKILL/scripts/python/report.py" --root "$ROOT" --serve
Construye output/report.html a partir de analysis.json + filas del libro mayor incrustadas en línea. Con --serve, abre http://127.0.0.1:8765/ y recarga en caliente cuando la base de datos/configuración cambia (vuelve a ejecutar analyze + vuelve a renderizar). Usa --refresh-analysis para forzar un reanálisis en una construcción única.
Interfaz del informe (output/report.html) — Panel híbrido Money.Audit
Estructura: marco de aplicación redondeado, barra lateral ligera con lista de años fiscales + navegación de secciones (scroll-spy), columna principal de ancho completo. Título: Lo que importa sobre tu dinero.
Estilo: Fraunces serif + Spline Sans UI; fondo cálido crema (#f7f6f3), acento dorado. No es un SaaS genérico gris.
Secciones (barra lateral): Resumen, Motor de ingresos, Gasto mensual, Áreas problemáticas, Post-mortem de negocio, Efectivo y movimientos, Plan de acción, Todas las categorías, Libro mayor (búsqueda + filtros).
Datos incrustados: const ANALYSIS = … y const LEDGER = … — sin fetch externo. El pie de página de la barra lateral muestra account_label de mapping (nunca codificar números de cuenta en la plantilla).
Movimiento: emil-design-eng — :active scale(0.98), transiciones de ancho de barra, seguro para movimiento reducido. Guía de estilo: references/ui_style_guide.md.
Plantilla: assets/report_template.html. Fixture ficticio para documentación: assets/fixtures/sample_analysis.json.
Al cambiar la interfaz del informe: edita la plantilla + guía de estilo; nunca confirmes output/report.html real. Regenera localmente mediante analyze → report.
Contenido del informe
- Resumen — puntuación de salud, métricas, tres cosas que diría el CFO.
- Ingresos / gastos / problemas — secciones orientadas a la decisión con desglose a categorías.
- Revisión de negocio — cuando
config/business.jsonestá presente. - Libro mayor — evidencia de transacciones buscable (primeras 350 coincidencias mostradas).
Banderas: --port N, --no-open, --refresh-analysis. Sin --serve, escribe output/report.html una vez (ejecuta analyze primero si falta analysis.json).
Metodología: references/financial_frameworks.md.
Nota: La interfaz híbrida Money.Audit usa la ruta de Python analyze + report. report.mjs de Node aún renderiza la plantilla CFO heredada para auditorías básicas sin analyze.
Estructura generada en la carpeta de auditoría
ROOT/
├── <archivos de estado de cuenta> # entrada (PDF/XLSX/XLS/CSV/TXT)
├── config/
│ ├── mapping.json # asignación de columnas (verificar después de ingest)
│ ├── categories.json # reglas de categoría (del ejemplo)
│ ├── business.json # opcional: ingresos/nómina/infraestructura de negocio
│ └── overrides.json # tus etiquetas añadidas durante el bucle
└── output/
├── audit.db # SQLite fuente de verdad
├── analysis.json # etapa analyze (solo local — PII)
├── uncategorized.csv # cola de revisión (regenerada en cada ejecución de categorize)
└── report.html # Panel Money.Audit (solo local — PII)
El skill solo escribe lo necesario: configuración editable, la base de datos SQLite que mantiene el estado entre etapas, la cola de revisión y el informe final. Los volcados intermedios (la vista previa de ingest, el JSON del informe) se imprimen/incrustan, no se escriben como archivos adicionales. mapping.json y audit.db deben persistir en disco porque cada etapa se ejecuta como un proceso separado.
Notas
- El mismo
mapping.json/config/ esquema SQLite funciona en ambos runtimes; puedes cambiar de runtime en medio de una auditoría. - Mantén los archivos de estado de cuenta sin procesar fuera del control de versiones (contienen PII).
- Para el esquema completo, matemáticas de validación y referencia de configuración, ver reference.md.
- Para marcos de análisis (tasa de ahorro, 50/30/20, benchmarks, lógica de recomendación), ver references/financial_frameworks.md.
Solicitudes comunes que este skill maneja
- "Auditar / categorizar mis estados de cuenta bancarios y hacer un informe" — pipeline completo.
- "¿Cuál es mi informe CFO Personal para el año fiscal 2024-25?" — usa el selector de período después del informe.
- "¿Cuál es mi tasa de ahorro y cómo la mejoro?" — resumen ejecutivo + plan de acción.
- "¿Dónde estoy gastando de más?" — inteligencia de gastos + contrafactuales.
- "¿Qué debería dejar de hacer / empezar / continuar?" — sección de plan de acción.
- "Pregunta a mi CFO sobre pista de aterrizaje / deuda / inversiones" — usa las indicaciones de Pregunta a tu CFO con tu agente.
- "Mejora la interfaz del informe / hazlo de ancho completo / arregla el diseño" — edita
assets/report_template.htmlsegún references/ui_style_guide.md; regenera localmente con analyze → report. Nunca confirmaroutput/report.html.