Brief del agente: Crear OpenClaw conectores de informes de fitness para Garmin, WHOOP, Speediance, y más
Un brief de implementación listo para el agente para crear OpenClaw conectores de informes de fitness en Garmin, WHOOP, Speediance, Cronometer, 8Sleep, instantáneas JSON normalizadas y repositorios públicos de GitHub.
Este artículo está pensado para entregarse a un agente de codificación de IA como un brief de implementación.
El objetivo no es clonar mi máquina privada ni hacer ingeniería inversa de mis archivos. El objetivo es que un agente lea esta página y construya conectores funcionales a los sistemas de fitness: Garmin, WHOOP, Speediance, Cronometer, 8Sleep, y Open Wearables de forma opcional.
La instrucción principal es sencilla: trata cada proveedor como un conector, persiste instantáneas JSON normalizadas y haz que el generador de informes consuma únicamente esas instantáneas. Esa separación convierte el caos de las API específicas de cada proveedor en un sistema que un agente puede construir.
El agente debe construir la misma clase de conexiones, no depender de mis rutas locales exactas:
- Garmin para cardio, carga de entrenamiento, ritmo, zonas de frecuencia cardíaca y detalle de actividades
- WHOOP para recuperación, HRV, RHR, sueño, strain y contexto de readiness
- Speediance para el historial de sesiones de fuerza, volumen, calorías, plantillas y detalle de ejercicios
- Cronometer para el contexto de nutrición
- 8Sleep para el contexto de sueño que llega tarde, cuando esté disponible
- OpenClaw como la capa de orquestación que ejecuta las sincronizaciones, normaliza los datos y genera los informes
También cubre los proyectos de GitHub, las API públicas, los contratos de datos, los modos de fallo y las comprobaciones de aceptación que un agente de implementación necesita para producir un stack funcional sin ver mi repositorio privado.
1. Tarea del agente
Construye un stack de informes de fitness OpenClaw local-first que pueda conectarse a los sistemas, normalizar sus datos y generar informes sin llamadas en vivo a los proveedores durante el renderizado.
El agente debe producir:
- Scripts conectores
Un trabajo de sincronización por sistema: Garmin, WHOOP, Speediance, Cronometer y 8Sleep cuando estén configurados. - Instantáneas crudas
Payloads derivados de JSON o CSV con marca de fecha para depurar cambios en los proveedores. - Contratos normalizados
Archivos JSON estables en los que el generador de informes pueda confiar incluso cuando cambien los payloads de los proveedores. - Informe matutino
Un informe que combine recuperación, sueño, readiness, carga de entrenamiento, nutrición y el plan del día. - Instantánea de entrenamiento adaptativo
Un plan Speediance/BJJ/carrera con fecha, derivado del readiness del mismo día y la carga reciente. - Informe nocturno
Una revisión plan vs. realidad que compare lo recomendado con la realidad de Garmin, WHOOP y Speediance. - Salida publicable
HTML estático y JSON legible por máquina que se pueda desplegar en GitHub Pages u otro host estático.
No construyas esto como "un script que llama a seis API y renderiza HTML en vivo". Eso es frágil.
2. Arquitectura que el agente debe implementar
Construye en cuatro capas:
- Capa de conectores
Un trabajo de sincronización por plataforma.
Capa de datos normalizados
Cada sincronización escribe instantáneas JSON estables.
3. Capa de análisis/informes
El código de informes lee únicamente JSON normalizado.
4. Capa de presentación
HTML, paneles, resúmenes diarios, publicaciones en Telegram, resúmenes de voz.
Esa separación es lo que hace que el sistema sea mantenible.
Contrato de implementación de IA
Agente, construye este contrato antes de escribir cualquier interfaz de panel:
- Entradas: solo variables de entorno y credenciales de proveedores; nunca codifiques secretos en los archivos fuente.
- Salidas de sincronización: una instantánea JSON sin procesar por cada extracción de proveedor, más un archivo JSON normalizado por proveedor.
- Entradas de informes: solo JSON normalizado. El generador de informes no debe llamar a Garmin, WHOOP, Speediance o Cronometer directamente.
- Modo de fallo: si un conector falla, conserva el archivo normalizado del último estado bueno conocido de ayer y marca esa fuente como obsoleta en el informe.
- Auditabilidad: conserva suficientes cargas útiles sin procesar para depurar cambios en la API del proveedor sin registrar tokens, cookies, contraseñas ni cabeceras privadas.
- Puerta de envío: las acciones de correo electrónico, voz, Telegram y entrenamiento adaptativo deben requerir datos de recuperación puntuados del mismo día. Aún se puede generar un informe web en modo degradado, pero el sistema no debe enviar coaching con confianza a partir de datos de recuperación obsoletos.
- Instantáneas del plan: los planes de entrenamiento adaptativo deben escribirse como instantáneas JSON diarias antes de enviarse a cualquier sitio. El informe nocturno puede entonces comparar el plan con lo que realmente ocurrió.
Variables de entorno mínimas para una compilación lista para el agente:
GARMIN_EMAIL=
GARMIN_PASSWORD=
WHOOP_CLIENT_ID=
WHOOP_CLIENT_SECRET=
WHOOP_ACCESS_TOKEN=
WHOOP_REFRESH_TOKEN=
SPEEDIANCE_USER_ID=
SPEEDIANCE_TOKEN=
SPEEDIANCE_REGION=Global
CRONOMETER_EXPORT_PATH=
EIGHTSLEEP_EMAIL=
EIGHTSLEEP_PASSWORD=
3. Definición de terminado
Un agente de implementación solo termina cuando estos artefactos existen y pueden regenerarse:
data/garmin/summary/latest.jsondata/whoop/normalized/latest.jsondata/speediance/normalized/history.jsondata/speediance/normalized/by_exercise.jsondata/nutrition/latest.jsondata/eightsleep/normalized/latest.json, si 8Sleep está configuradodata/training_plans/YYYY-MM-DD_morning.jsonreports/morning/latest.htmlreports/nightly/latest.html- una puerta de envío que retenga los envíos de correo electrónico, voz, Telegram y entrenamiento adaptativo cuando falten datos de recuperación WHOOP puntuados del mismo día
- advertencias de fuentes obsoletas cuando un conector falla pero los datos normalizados del último estado bueno conocido de ayer están disponibles
- una comprobación de no-secretos que demuestra que los tokens, cookies, contraseñas y cabeceras privadas no se incluyeron en el repositorio
Si el agente no puede autenticarse con un proveedor durante el desarrollo, debe implementar igualmente la interfaz del conector, .env.example, fixtures falsos, normalizador, manejo de fuentes obsoletas y la integración de informes.
4. Proyectos públicos y referencias de fuentes
Estas son las piezas públicas que un agente debe usar como referencias de implementación.
Lista de comprobación rápida de GitHub/API:
- Conector Garmin:
https://github.com/cyberjunky/python-garminconnect - Contexto de autenticación heredado de Garmin:
https://github.com/matin/garth - API oficial para desarrolladores de WHOOP:
https://developer.whoop.com/api - Extracción pública de Speediance para esta compilación:
https://github.com/clawdassistant85-netizen/speediance-smartgym-workout-manager - Fork funcional de Speediance del que se extrajo esto:
https://github.com/ANPC86/SmartGymWorkoutManager - Referencia upstream/original de Speediance:
https://github.com/hbui3/UnofficialSpeedianceWorkoutManager - Referencia de generador/plantilla de informe:
https://github.com/tobyglenn/scriptsJinja - Exportaciones/integraciones de Cronometer:
https://cronometer.com/
OpenClaw
- Plataforma/orquestador: OpenClaw
- Función: programar trabajos de sincronización, ejecutar transformaciones, generar informes y publicar resultados
Garmin
- Cliente Python principal: cyberjunky/python-garminconnect
GitHub:https://github.com/cyberjunky/python-garminconnect - Librería de autenticación heredada que antes era importante: matin/garth
GitHub:https://github.com/matin/garth - Nota de estado:
garthestá obsoleto;python-garminconnectahora usa flujos de autenticación más recientes de Garmin y es la opción sobre la que se debe construir.
WHOOP
- Documentación de la API oficial para desarrolladores:
https://developer.whoop.com/api - Superficie de la API pública: endpoints OAuth2 + REST para recuperación, ciclos, sueño, entrenamientos, perfil y medidas corporales
- Existen wrappers opcionales de la comunidad, pero un conector creado por el agente debe anclarse a la API oficial para desarrolladores de WHOOP siempre que sea posible.
Speediance
- Referencia de implementación pública práctica de Speediance: ANPC86/SmartGymWorkoutManager
GitHub:https://github.com/ANPC86/SmartGymWorkoutManager - Linaje del proyecto upstream / referencia pública original: hbui3/UnofficialSpeedianceWorkoutManager
GitHub:https://github.com/hbui3/UnofficialSpeedianceWorkoutManager - Usar el fork de ANPC86 SmartGymWorkoutManager como referencia práctica de conexión porque contiene trabajo útil sobre historial, exportaciones, depuración de la API, manejo de zonas horarias y manejo de unidades.
- Esta es una integración no oficial de Speediance y debe tratarse como inestable por defecto.
Nutrición
- Sitio del producto / exportaciones / integraciones de Cronometer:
https://cronometer.com/ - Tratar Cronometer como una fuente estructurada de exportación de nutrición, no como una dependencia mágica directa del informe.
5. Actualizaciones de producción que el agente debe preservar
La versión actual de este stack tiene algunos comportamientos importantes que el agente debe preservar.
Máquina de un único propietario
El pipeline de fitness debe tener una máquina autoritativa siempre encendida. No se debe permitir que dos ordenadores diferentes generen y desplieguen informes contra el mismo repositorio de salida.
La máquina activa es la responsable de las tareas de sincronización con proveedores, la generación de informes, la generación adaptativa de entrenamientos, el despliegue en GitHub Pages y las comprobaciones del watchdog.
Otras máquinas pueden consultar los informes o alojar paneles locales, pero no deben regenerar los informes de fitness.
Pipeline secuencial en lugar de conjeturas escalonadas de cron
Los pipelines matutino y nocturno deben ejecutarse como fases ordenadas:
- sincronizar datos de proveedores
- verificar los datos requeridos del día
- generar informes
- desplegar
- enviar notificaciones
- generar resúmenes de voz, si se utilizan
- ejecutar la validación del watchdog
El error de antes era programar esos pasos a intervalos fijos de reloj confiando en que cada fase anterior hubiera terminado. El patrón más adecuado es un único orquestador que ejecute cada fase solo después de que la anterior haya finalizado correctamente.
Barrera de recuperación WHOOP del mismo día
Para este stack, la recuperación WHOOP del día es una barrera obligatoria para el coaching. Si falta la recuperación de hoy, el sistema puede seguir publicando un informe web con avisos de fuente obsoleta, pero debe retener el envío de correos, voz, coaching por Telegram y entrenamientos adaptativos.
Esa única regla evita el peor modo de fallo: una recomendación aparentemente sólida basada en la recuperación de ayer.
Gestión de datos tardíos de 8Sleep
8Sleep puede actualizarse después de la primera ejecución matutina. Una reejecución debe forzar la actualización de hoy y de ayer antes de regenerar, en lugar de fiarse de un archivo JSON local existente solo porque exista.
Solo zonas de FC reales de Garmin
No inventes distribuciones de zonas de frecuencia cardíaca a partir de la frecuencia cardíaca media. Si el detalle de actividad de Garmin incluye datos de tiempo por zona, utilízalo. Si no, oculta ese gráfico o márcalo como no disponible.
Revisión de la ejecución del plan
El informe nocturno funciona mejor cuando compara el plan del día con los datos reales del día:
- entrenamiento BJJ planificado vs entrenamiento BJJ de WHOOP
- sesión Speediance planificada vs sesiones Speediance completadas
- carrera planificada vs distancia de carrera de Garmin
- pasos planificados vs pasos de Garmin
Esto convierte el informe nocturno en un ciclo de retroalimentación en lugar de ser solo un resumen.
Modo sombra de Open Wearables
Open Wearables es útil como futura capa de abstracción, pero no migraría de golpe un sistema de informes personales que ya esté funcionando. La migración más segura es el modo sombra:
- mantener el pipeline basado en archivos existente como autoritativo
- importar o replicar los datos de Garmin/WHOOP en Open Wearables
- exportar los datos de Open Wearables de vuelta a archivos JSON sombra
- comparar los archivos sombra con los archivos de producción
- promover solo cuando coincidan los recuentos, las fechas y los registros del mismo día
Los archivos sombra nunca deben sobrescribir las entradas de producción durante la fase piloto.
6. Garmin: la capa de cardio y detalle de actividad
Si WHOOP responde a «¿cómo de recuperado estoy?», Garmin responde a «¿qué hice exactamente?»
Garmin es donde el informe obtiene:
- distancia
- ritmo y velocidad
- duración
- FC media y máxima
- zonas de frecuencia cardiaca
- cadencia
- potencia
- efecto de entrenamiento
- metadatos de la actividad
- detalle cardiorespiratorio y de entrenamiento más amplio que WHOOP no enfatiza con tanta riqueza
Repositorio público a usar
Recomendado: cyberjunky/python-garminconnect
GitHub:
https://github.com/cyberjunky/python-garminconnect
Por qué importa:
- está posicionado activamente como el wrapper Python de Garmin Connect que conviene usar
- expone una superficie de endpoints de Garmin muy amplia
- incluye ejemplos y patrones de gestión de tokens
- sustituyó suposiciones de autenticación antiguas que se rompieron con cambios previos de Garmin
Nota importante de compatibilidad con Garmin
Históricamente, muchas builds utilizaban garth.
GitHub:
https://github.com/matin/garth
Pero garth ahora está explícitamente obsoleto. Esto importa porque un agente no debería basar una nueva implementación en una autenticación obsoleta.
Ejemplo mínimo ejecutable de Garmin
from garminconnect import Garmin
from datetime import date
from pathlib import Path
import json
import os
email = os.environ["GARMIN_EMAIL"]
password = os.environ["GARMIN_PASSWORD"]
client = Garmin(email=email, password=password)
client.login()
today = date.today().isoformat()
stats = client.get_stats(today)
activities = client.get_activities_by_date(today, today)
payload = {
"date": today,
"stats": stats,
"activities": activities,
}
out = Path("data/garmin/raw")
out.mkdir(parents=True, exist_ok=True)
(out / f"{today}.json").write_text(json.dumps(payload, indent=2))
Qué normalizar desde Garmin
No vuelques los payloads crudos de Garmin directamente en la lógica de tu informe final. Normalízalos primero en campos como:
calendarDatetotalStepsrestingHeartRatesleepingSecondsbodyBatteryactivityNameactivityTypedurationSecondsdistanceMetersdistanceMilesaverageHRmaxHRcaloriestrainingEffectcadencepower
Patrón de almacenamiento recomendado
data/garmin/raw/YYYY-MM-DD.jsondata/garmin/normalized/YYYY-MM-DD.jsondata/garmin/summary/latest.json
Esto te ofrece tanto reproducibilidad como acceso rápido al informe.
7. WHOOP: la capa de recuperación y disposición
WHOOP es lo que hace que los informes resulten útiles como motor de decisión en lugar de ser solo un registro de actividades.
Aporta:
- puntuación de recuperación
- HRV
- frecuencia cardiaca en reposo
- rendimiento del sueño
- carga (strain)
- contexto de ciclo
- encuadre de disposición para recomendaciones matutinas y nocturnas
API pública a usar
Utiliza la API oficial para desarrolladores de WHOOP:
- Documentación:
https://developer.whoop.com/api
Grupos de endpoints relevantes:
/developer/v2/cycle/developer/v2/recovery/developer/v2/activity/sleep/developer/v2/activity/workout/developer/v2/user/profile/basic/developer/v2/user/measurement/body
Limitación crítica
Uno de los hallazgos de implementación más importantes: los datos del diario no están disponibles en la API de WHOOP.
Si quieres respuestas del diario o anotaciones de hábitos, no puedes confiar en un endpoint público de la API de WHOOP para eso. Las opciones prácticas son:
- exportación manual en CSV desde WHOOP
- tu propia capa de diario paralela
- metadatos separados que adjuntas después de la sincronización
Esa limitación debería mencionarse claramente en el artículo porque afecta a cualquier desarrollo serio.
Ejemplo ejecutable mínimo de WHOOP
from pathlib import Path
import json
import os
import requests
BASE = "https://api.prod.whoop.com/developer/v2"
TOKEN = os.environ["WHOOP_ACCESS_TOKEN"]
headers = {"Authorization": f"Bearer {TOKEN}"}
def get(path):
response = requests.get(f"{BASE}{path}", headers=headers, timeout=30)
response.raise_for_status()
return response.json()
payload = {
"recovery": get("/recovery"),
"sleep": get("/activity/sleep"),
"workouts": get("/activity/workout"),
}
out = Path("data/whoop/raw")
out.mkdir(parents=True, exist_ok=True)
(out / "latest.json").write_text(json.dumps(payload, indent=2))
Qué normalizar desde WHOOP
Normaliza en campos como:
recovery_scorehrv_rmssd_milliresting_heart_ratespo2_percentageskin_temp_celsiussleep_performance_percentagerespiratory_ratestraincycle_startcycle_endworkout_sport_name
Patrón de almacenamiento recomendado
data/whoop/raw/recovery.jsondata/whoop/raw/sleep.jsondata/whoop/raw/workouts.jsondata/whoop/normalized/latest.json
8. Speediance: la capa de entrenamiento de fuerza
Speediance es el conector más inusual de toda la pila.
A diferencia de Garmin y WHOOP, esta no es una plataforma de desarrollo pública oficial y bien definida. El agente debería usar estos repositorios públicos como referencias de conexión:
Extracción/referencia pública: https://github.com/clawdassistant85-netizen/speediance-smartgym-workout-manager
ANPC86/SmartGymWorkoutManager
GitHub: https://github.com/ANPC86/SmartGymWorkoutManager
Ese repositorio es en sí mismo un fork personal / continuación del proyecto Speediance público original:
hbui3/UnofficialSpeedianceWorkoutManager
GitHub: https://github.com/hbui3/UnofficialSpeedianceWorkoutManager
Estos repositorios son el punto de partida importante porque muestran cómo:
- autenticar contra los endpoints de Speediance
- inspeccionar datos de entrenamientos y respuestas de la API
- navegar/exportar el historial de entrenamiento
- gestionar plantillas/entrenamentos de forma amigable para escritorio
- manejar problemas prácticos como la visualización de zonas horarias y el manejo de pesos en sistema imperial/métrico
Por qué importan estos repositorios
Utiliza el fork de ANPC86 SmartGymWorkoutManager como base práctica para el patrón de integración de Speediance, conservando al mismo tiempo la referencia upstream hbui3 para la trazabilidad. Juntos, son las referencias públicas más claras para trabajar con datos Speediance fuera de la aplicación oficial.
Advertencia de estabilidad
El proyecto original señala que Speediance ha estado implementando mejoras de seguridad. Eso significa que:
- esta integración puede romperse
- las cabeceras y el comportamiento de autenticación pueden cambiar
- los endpoints pueden cambiar de ubicación
- deberías aislar este conector detrás de un paso de normalización para que tus informes sobrevivan a los cambios del proveedor
Patrón ejecutable mínimo para Speediance
Si utilizas ANPC86/SmartGymWorkoutManager como punto de partida, consultando al mismo tiempo el upstream hbui3/UnofficialSpeedianceWorkoutManager para conocer el contexto original, el enfoque limpio es:
- Ejecuta su app o capa cliente en local
- Autentícate con tu cuenta Speediance
- Extrae el historial de entrenamientos de los métodos de la API que expone
- Exporta JSON normalizado a tu propio directorio de datos
Pseudoejemplo utilizando ese patrón de cliente:
# Adapta esto alrededor del api_client.py en:
# https://github.com/clawdassistant85-netizen/speediance-smartgym-workout-manager
from api_client import SpeedianceClient
from datetime import date
from pathlib import Path
import json
import os
client = SpeedianceClient()
success, msg, debug = client.login(
os.environ["SPEEDIANCE_USER_ID"],
os.environ["SPEEDIANCE_TOKEN"],
)
if not success:
raise RuntimeError(msg)
start_date = os.environ.get("SPEEDIANCE_START_DATE", "2026-01-01")
end_date = date.today().isoformat()
records = client.get_training_data(start_date, end_date)
out = Path("data/speediance/raw")
out.mkdir(parents=True, exist_ok=True)
(out / "history.json").write_text(json.dumps(records, indent=2))
Qué normalizar de Speediance
Normaliza en campos como:
training_iddatetitleduration_secondscaloriestotal_volumeexercise_counttemplate_nameplanned_durationactual_durationexercise_breakdownestimated_1rm
Modelo de datos de buenas prácticas
Para un sistema de informes serio, mantén dos índices:
- bySession
- un registro por entrenamiento completado
- byExercise
- un flujo de registros por nombre de movimiento
- incluye peso, repeticiones, lado, id de sesión, marca temporal
Esa estructura hace que las gráficas de progresión y la detección de PR resulten triviales más adelante.
Patrón de almacenamiento recomendado
data/speediance/raw/monthly/YYYY-MM.jsondata/speediance/normalized/history.jsondata/speediance/normalized/by_exercise.jsondata/speediance/dashboard/latest.json
Capturas adaptativas de entrenamientos Speediance
La versión más avanzada de esta compilación no solo lee los entrenamientos Speediance completados.
También crea entrenamientos planificados a partir de datos de preparación en tiempo real.
El patrón útil es:
- Cargar la recuperación de WHOOP del mismo día, la carga actual, la carga BJJ, la batería corporal Garmin, la FC en reposo, la carga reciente de carrera, el clima y el historial reciente del plan Speediance.
- Clasificar el día en una categoría como
build,maintain,recover,protectopost_bjj_brutal. - Seleccionar un implemento Speediance para todo el entrenamiento, normalmente asas, barra o cuerda.
- Elegir ejercicios en el dispositivo solo para el entrenamiento principal Speediance.
- Añadir de cero a dos accesorios fuera de Speediance solo cuando la recuperación lo permita.
- Escribir el plan en
data/training_plans/YYYY-MM-DD_context.json. - Usar la instantánea tanto para la recomendación matutina como para la revisión nocturna de la ejecución del plan.
Para el control de repetición, comparar la firma del nuevo entrenamiento con las instantáneas recientes del plan. La versión de producción utiliza una ventana de unicidad móvil que crece hasta 30 días, y siempre marca el título del entrenamiento con la fecha de hoy para que un entrenamiento que reaparece siga siendo actual y se pueda buscar.
9. Cronometer: la capa de contexto nutricional
Sea cual sea la aplicación de nutrición exacta que utilices, la función es la misma: proporcionar al informe contexto sobre la ingesta energética.
Esto importa porque la carga de entrenamiento sin contexto nutricional lleva a malas conclusiones.
El informe debería poder preguntar:
- ¿La recuperación fue baja porque la carga de entrenamiento fue alta?
- ¿O porque el sueño fue pobre y la ingesta calórica fue baja?
- ¿Estuvo el atleta mal alimentado en relación con el rendimiento?
Consejos prácticos de implementación
No depender de una API de nutrición en tiempo real en el momento de renderizar. Usar una de:
- Exportación CSV
- Ingestión por webhook
- Sincronización programada a JSON normalizado
Normalizar en campos como:
calories_consumedprotein_gcarbs_gfat_gfiber_gtarget_caloriesestimated_deficit
Patrón de almacenamiento recomendado
data/nutrition/raw/YYYY-MM-DD.csvdata/nutrition/normalized/YYYY-MM-DD.jsondata/nutrition/latest.json
10. 8Sleep: la capa de contexto del sueño de llegada tardía
8Sleep es opcional, pero si está configurado, el agente debe tratarlo como cualquier otro conector: sincronizar primero, normalizar después, renderizar desde los archivos al final.
El comportamiento importante es el manejo de datos tardíos. Los datos del sueño pueden cambiar después de la primera ejecución matutina, por lo que una reejecución manual o un reintento programado debe forzar la actualización tanto de hoy como de ayer antes de regenerar el informe.
Normalizar campos como:
sleep_scoresleep_startsleep_endtime_in_bed_secondstime_asleep_secondshrvresting_heart_ratetemperature_adjustmentsaway_mode
Patrón de almacenamiento recomendado:
data/eightsleep/raw/YYYY-MM-DD.jsondata/eightsleep/normalized/YYYY-MM-DD.jsondata/eightsleep/normalized/latest.json
11.
Lo que OpenClaw realmente hace en esta pila
OpenClaw no es la fuente de datos. Es la capa de orquestación y razonamiento.
Su trabajo es:
- ejecutar trabajos de sincronización según una programación
- almacenar salidas estables
- comparar fuentes
- generar el HTML del informe
- publicar enlaces
- producir resúmenes amigables para humanos a partir de los datos normalizados
Esto significa que el código de informes debe leer archivos como:
data/garmin/summary/latest.jsondata/whoop/normalized/latest.jsondata/speediance/normalized/history.jsondata/nutrition/latest.jsondata/eightsleep/normalized/latest.json
El generador de informes nunca debería necesitar saber cómo funciona la autenticación de Garmin ni cómo cambiaron los encabezados de Speediance esta semana.
12. Estructura de directorios construible por un agente
Esta es una estructura que un agente puede crear antes de que cualquier autenticación real de proveedor funcione:
project/
data/
garmin/
raw/
normalized/
summary/
whoop/
raw/
normalized/
speediance/
raw/
normalized/
dashboard/
nutrition/
raw/
normalized/
eightsleep/
raw/
normalized/
training_plans/
scripts/
sync_garmin.py
sync_whoop.py
sync_speediance.py
sync_nutrition.py
sync_eightsleep.py
gate_same_day_recovery.py
build_adaptive_plan.py
build_report.py
reports/
morning/
latest.html
nightly/
latest.html
frontend/
data/
La estructura de archivos es parte de la interfaz. Hazla lo suficientemente sencilla para que un agente futuro pueda inspeccionar el sistema, encontrar cada conector, volver a ejecutar una sola sincronización y comparar las cargas útiles sin procesar con las salidas normalizadas.
13. Ejemplo de patrón para el generador de informes
Una vez que cada conector escribe JSON normalizado, el código real del informe se vuelve simple.
import json
from pathlib import Path
base = Path("data")
garmin = json.loads((base / "garmin/summary/latest.json").read_text())
whoop = json.loads((base / "whoop/normalized/latest.json").read_text())
speediance = json.loads((base / "speediance/normalized/history.json").read_text())
nutrition = json.loads((base / "nutrition/latest.json").read_text())
eightsleep_path = base / "eightsleep/normalized/latest.json"
eightsleep = json.loads(eightsleep_path.read_text()) if eightsleep_path.exists() else {}
summary = {
"recovery": whoop.get("recovery_score"),
"hrv": whoop.get("hrv_rmssd_milli"),
"rhr": whoop.get("resting_heart_rate"),
"steps": garmin.get("totalSteps"),
"body_battery": garmin.get("bodyBattery"),
"lifting_volume": speediance.get("today", {}).get("total_volume"),
"calories_in": nutrition.get("calories_consumed"),
"sleep_score": eightsleep.get("sleep_score"),
}
html = f"""
<html>
<body>
<h1>Informe diario de fitness</h1>
<ul>
<li>Recuperación: {summary['recovery']}</li>
<li>HRV: {summary['hrv']}</li>
<li>RHR: {summary['rhr']}</li>
<li>Pasos: {summary['steps']}</li>
<li>Body Battery: {summary['body_battery']}</li>
<li>Volumen de pesas: {summary['lifting_volume']}</li>
<li>Calorías ingeridas: {summary['calories_in']}</li>
<li>8Sleep Puntuación: {summary['sleep_score']}</li>
</ul>
</body>
</html>
"""
out = Path("reports/morning")
out.mkdir(parents=True, exist_ok=True)
(out / "latest.html").write_text(html)
Aquí es donde todo el diseño da sus frutos: una vez que la capa de sincronización es estable, la capa de informes se vuelve aburrida de la mejor manera posible.
14. Para qué sirve realmente cada conector
Este es el modelo mental más sencillo:
WHOOP
Úsalo para:
- recuperación
- HRV
- RHR
- rendimiento del sueño
- carga
- encuadre de la disposición
Garmin
Úsalo para:
- detalle de carrera y cardio
- ritmo, potencia, cadencia
- zonas de FC
- efecto de entrenamiento
- historial detallado de actividades
Speediance
Úsalo para:
- historial de entrenamientos de fuerza
- volumen total
- detalle del ejercicio
- ejecución de la sesión planificada frente a la real
- progresión a nivel de movimiento si construyes indexación por ejercicio
Aplicación de nutrición
Úsala para:
- ingesta calórica
- contexto de macronutrientes
- detección de alimentación insuficiente
8Sleep
Úsalo para:
- detalle del sueño que llega tarde
- duración y puntuación del sueño específicas de cada cama
- comprobaciones cruzadas del contexto del sueño frente a WHOOP y Garmin
OpenClaw los combina todos en una única superficie de informe y recomendaciones.
15. Entregables de conexión por sistema
Esta es la lista de comprobación que el agente de implementación debe satisfacer antes de pulir la interfaz del informe.
Puntos de conexión de Garmin
- Biblioteca:
garminconnectdecyberjunky/python-garminconnect - Autenticación: correo electrónico/contraseña de Garmin Connect con la gestión de tokens/sesiones de la biblioteca
- Cadencia de extracción: sincronización diaria por la mañana, más sincronización opcional tras el entrenamiento
- Extracciones mínimas:
- estadísticas diarias de pasos, FC en reposo, segundos de sueño, body battery, calorías
- actividades por fecha para sesiones de carrera,骑行/cardio
- detalle de actividad, cuando esté disponible, para zonas de FC, ritmo, cadencia, potencia, efecto de entrenamiento
- Salida normalizada:
data/garmin/summary/latest.json
Puntos de conexión WHOOP
- Documentación de la API:
https://developer.whoop.com/api - Autenticación: token de acceso OAuth2 + flujo de token de actualización
- URL base:
https://api.prod.whoop.com/developer/v2 - Grupos de endpoints mínimos:
/cyclepara contexto de strain/ciclo/recoverypara puntuación de recuperación, HRV y FC en reposo/activity/sleeppara rendimiento del sueño y horarios de sueño/activity/workoutpara entrenamientos y datos de strain de WHOOP/user/profile/basicy/user/measurement/bodypara contexto de perfil/cuerpo cuando sea necesario
- Salida normalizada:
data/whoop/normalized/latest.json
Puntos de conexión Speediance
- Extracción pública para esta build:
https://github.com/clawdassistant85-netizen/speediance-smartgym-workout-manager - Referencia upstream:
https://github.com/hbui3/UnofficialSpeedianceWorkoutManager - Autenticación: flujo no oficial basado en token/user-id expuesto por la capa cliente de SmartGym
- Extracciones mínimas:
- historial de entrenamientos
- detalle de ejercicio/sesión
- metadatos de entrenamientos/plantillas personalizados si quieres informes de planificado vs. real
- captura de respuestas sin procesar de API/debug sin secretos
- Salidas normalizadas:
data/speediance/normalized/history.jsondata/speediance/normalized/by_exercise.json
Puntos de conexión de Cronometer
- Fuente pública: exports/integraciones de
https://cronometer.com/ - Enfoque de implementación recomendado: exportación CSV o entrega programada de archivos, no una dependencia de API en tiempo de renderizado
- Campos mínimos: fecha, calorías, proteínas, carbohidratos, grasas, fibra y cualquier micronutriente que desees incluir en el análisis de recuperación
- Salida normalizada:
data/nutrition/latest.json
Puntos de conexión 8Sleep
- Autenticación: flujo de inicio de sesión/sesión respaldado por variables de entorno, sin credenciales en el código fuente
- Cadencia de extracción: sincronización matutina más soporte de reejecución/actualización para hoy y ayer
- Extracciones mínimas:
- puntuación de sueño
- horarios de sueño
- tiempo dormido y tiempo en cama
- HRV y FC en reposo cuando estén disponibles
- temperatura y contexto del modo ausente cuando estén disponibles
- Salida normalizada:
data/eightsleep/normalized/latest.json
Punto de conexión de generación de informes
El generador de informes solo debería leer archivos normalizados estables y snapshots de planes. Una forma práctica sería:
data/garmin/summary/latest.json
data/whoop/normalized/latest.json
data/speediance/normalized/history.json
data/speediance/normalized/by_exercise.json
data/nutrition/latest.json
data/eightsleep/normalized/latest.json
data/training_plans/YYYY-MM-DD_morning.json
data/training_plans/YYYY-MM-DD_post_bjj.json
Esa es la superficie de conexión real. Todo lo que está aguas arriba puede romperse y arreglarse de forma independiente.
16. Las verdaderas reglas de implementación
Si un agente va a construir esto con éxito, estas reglas importan más que cualquier fragmento de código individual:
Normaliza cada proveedor en tu propio esquema
Nunca dejes que un informe dependa de la forma del payload del proveedor.Conserva instantáneas (snapshots) sin procesar
Cuando una sincronización se rompe, los payloads sin procesar te salvan.
Nunca renderices desde APIs en vivo si el informe es sensible al tiempo
Sincroniza primero, renderiza después.
Trata las integraciones no oficiales como adaptadores desechables
Especialmente Speediance.Haz que Garmin y WHOOP se complementen, no que compitan
WHOOP = preparación. Garmin = detalle de ejecución.Modela los datos de fuerza tanto a nivel de sesión como de ejercicio
De lo contrario, el informe de progresión se queda superficial.Condiciona el entrenamiento a la preparación de hoy, no a la de ayer
Si falta la recuperación del mismo día, el sistema debería degradarse a informes solo web.Guarda el plan antes de juzgar el día
Una puntuación de adherencia nocturna solo funciona si el plan de la mañana o post-BJJ se almacenó como dato.Prueba los nuevos backends en modo sombra
Open Wearables o cualquier otra capa de abstracción debería demostrar que puede igualar los archivos de producción actuales antes de convertirse en la fuente de verdad.
Lista final de referencias de implementación
Estas son las referencias públicas que un agente de codificación de IA debería recibir primero al implementar este sistema:
- OpenClaw como capa de orquestación
- Conector de Garmin:
https://github.com/cyberjunky/python-garminconnect - Contexto histórico de autenticación de Garmin:
https://github.com/matin/garth(obsoleto; usar como contexto, no como centro de una nueva construcción) - API oficial para desarrolladores de WHOOP:
https://developer.whoop.com/api - Extracción pública de Speediance para esta compilación:
https://github.com/clawdassistant85-netizen/speediance-smartgym-workout-manager - Referencia upstream/original de Speediance:
https://github.com/hbui3/UnofficialSpeedianceWorkoutManager - Referencia del generador/plantilla de informe:
https://github.com/tobyglenn/scriptsJinja - Exportaciones de nutrición de Cronometer:
https://cronometer.com/ - Contrato del conector 8Sleep: sincronización respaldada por entorno que escribe
data/eightsleep/normalized/latest.json
Si vas a entregar este artículo a Claude Code, Codex, OpenClaw, u otro agente de implementación, la instrucción correcta es: primero construye los conectores, segundo escribe instantáneas JSON normalizadas, tercero aplica la puerta de recuperación del mismo día, y por último construye el renderizador de informes. No empieces diseñando el informe HTML final.