¿Qué hace subs — Analizador de gastos en suscripciones SaaS?
Analiza los gastos recurrentes en suscripciones del usuario a partir de extractos bancarios/tarjetas de crédito CSV y recibos de correo electrónico. Produce un resumen de gastos, identifica desperdicios, rastrea renovaciones y recomienda ahorros.
El ledger es la columna vertebral
subscriptions.yaml en el espacio de trabajo es la fuente única de verdad. Cada ejecución reconcilia datos nuevos en él — nunca vuelve a derivar todo desde cero. Esto es lo que hace posible el seguimiento de renovaciones y la consistencia entre ejecuciones, y permite calcular "desperdicio" (una suscripción que cobró durante meses y luego desaparece repentinamente = caducada o que vale la pena cancelar). Nunca sobrescribas el ledger por completo; reconcílialo.
Esquema de entrada del ledger (una entrada por suscripción):
- vendor: GitHub # nombre canónico
amount: 4.00 # cargo más reciente
currency: USD
cycle: monthly # weekly | monthly | quarterly | semiannual | annual
category: Dev tools
first_seen: 2025-01-12 # fecha ISO del cargo más antiguo conocido
last_seen: 2026-06-03 # fecha ISO del cargo más reciente
next_renewal: 2026-07-03 # last_seen + un ciclo
status: active # active | price_hike | lapsed? | cancelled
notes: "was 4.00 since signup"
Requisito previo: un conector de Gmail
Esta skill lee recibos de suscripciones de Gmail a través de un conector/MCP de Gmail disponible para tu agente de codificación (por ejemplo, el conector de Gmail de Claude Code). Antes del paso 1, confirma que tu agente tenga herramientas de búsqueda/lectura de Gmail (un par search_threads / get_thread, o equivalente). Si no hay integración con Gmail disponible, detente e indica al usuario que habilite una, luego vuelve a ejecutar la skill. Detalles y consultas en email-receipts.md.
Proceso
Trabaja a través de estos pasos en orden. No reportes hasta el paso 5.
0. Localizar el espacio de trabajo
Usa el directorio de trabajo actual como espacio de trabajo. Asegúrate de que existan data/statements/, data/receipts/ y reports/ (crearlos si faltan). Carga subscriptions.yaml si existe; de lo contrario, trata el ledger como vacío.
Completado cuando: los directorios del espacio de trabajo existen y el ledger está cargado (posiblemente vacío).
Si data/statements/ está vacío Y aún no existe subscriptions.yaml Y el usuario no está usando Plaid (sección siguiente), dile al usuario que coloque sus extractos bancarios/tarjetas CSV en data/statements/ y detente — los CSV son la columna vertebral de la detección de recurrencia.
1. Recopilar entradas
Datos bancarios a través de la CLI de Plaid (preferido — sin exportación manual de CSV): asegúrate de que la CLI esté lista y extrae las transacciones a data/statements/plaid-transactions.csv según plaid.md. De lo contrario, confía en los CSV que el usuario haya colocado en data/statements/.
Luego enumera cada CSV en data/statements/. Extrae los recibos de suscripciones de Gmail según email-receipts.md, y también lee cualquier archivo .eml/.txt complementario en data/receipts/.
Completado cuando: cada CSV en data/statements/ está enumerado, y la búsqueda de recibos de Gmail ha regresado (o la ejecución se detuvo por falta de conector).
2. Detectar cargos recurrentes
Ejecuta el detector determinista sobre cada CSV de extracto (incluido el derivado de Plaid) — no inspecciones filas manualmente. <skill-dir> es el directorio propio de esta skill (en Claude Code: ~/.claude/skills/subs/):
python3 <skill-dir>/scripts/detect_recurring.py data/statements/*.csv
Para candidatos de confianza low y casos extremos de normalización de comerciantes, consulta recurrence-detection.md. Combina estos candidatos con los recibos de Gmail recopilados en el paso 1 — los recibos detectan suscripciones anuales que un extracto corto pasa por alto e identifican descriptores vagos.
Completado cuando: cada candidato recurrente tiene un comerciante, cadencia, monto y fecha de última aparición.
3. Reconciliar en el ledger
Reconcilia los candidatos en subscriptions.yaml:
- Nuevo comerciante → agrega una entrada; categoriza según categories.md.
- Existente → actualiza
last_seenynext_renewal; si el monto aumentó, establecestatus: price_hikey registra el monto anterior ennotes. - En el ledger pero ausente de datos recientes (sin cargo dentro de ~1.5 ciclos desde hoy) → establece
status: lapsed?.
Completado cuando: el status de cada entrada del ledger es uno de active | price_hike | lapsed? | cancelled, y cada candidato se asigna exactamente a una entrada del ledger.
4. Analizar
A partir del ledger reconciliado, calcula los cuatro:
- (a) Resumen de gastos — total mensual y total anualizado, agrupado por categoría, por comerciante y por ciclo de facturación. Normaliza cada entrada a una cifra mensual ($/mes): anual ÷ 12, semestral ÷ 6, trimestral ÷ 3, mensual × 1, bimensual × 2.17, semanal × 4.33, semimensual × 2. Los informes reutilizan este $/mes (fuente única de verdad).
- (b) Desperdicio — duplicados (mismo servicio dos veces), herramientas superpuestas (dos productos en la misma categoría que hacen lo mismo), aumentos de precio (
status: price_hike) y caducados/sin uso (status: lapsed?). - (c) Próximas renovaciones — entradas cuyo
next_renewalcae dentro de los próximos 60 días, primero las más próximas. - (d) Recomendaciones de ahorro — cambios de anual a mensual, degradaciones, consolidaciones y cancelaciones. Cada una debe citar una entrada del ledger y un impacto en dólares.
Completado cuando: los cuatro elementos están producidos y cada recomendación cita una entrada + una cifra en dólares.
5. Informar
Guarda el ledger, luego escribe ambos informes a partir de él:
- markdown
reports/<YYYY-MM-DD>-subscriptions.mdsegún report-template.md; - un dashboard HTML autocontenido
reports/<YYYY-MM-DD>-subscriptions.htmlsegún html-report.md, y ábrelo (open <path>).
Luego presenta un resumen conciso en el chat (totales principales + las 3 mejores acciones).
Completado cuando: ambos informes contienen el resumen de gastos, indicadores de desperdicio, próximas renovaciones y recomendaciones clasificadas, y subscriptions.yaml está guardado.