# 0025 — Catálogo de automatizaciones cron + scaffolder

## Objetivo

Crear un directorio `crons/` como catálogo central de automatizaciones nombradas, y un conjunto de
scripts en `dev-scripts/cron/` para crear nuevas automatizaciones, listarlas y aplicarlas a agentes
sin editar YAML a mano. Evolución directa de la infraestructura creada en el issue 0005.

## Contexto

- `shell/cron/` ya implementa el scheduler con `send_message` y `llm_prompt` (issue 0005)
- Las automatizaciones se definen en cada `agents/<id>/config.yaml` bajo `schedules:`, lo que las
  dispersa y dificulta reutilizarlas entre agentes
- No hay forma de crear una nueva automatización sin editar YAML a mano y conocer la estructura
- No existe un catálogo centralizado ni scripts de gestión
- Depende de: issue 0005 (completado)

## Arquitectura

```
crons/                              NEW — catálogo de automatizaciones nombradas
  good-morning/
    schedule.yaml                   NEW — spec (description, cron, action, output_room por defecto)
    prompts/
      message.md                    NEW — plantilla de mensaje
  daily-summary/
    schedule.yaml                   NEW
    prompts/
      prompt.md                     NEW

dev-scripts/cron/                   NEW — herramientas de gestión
  new.sh                            NEW — scaffolder interactivo
  list.sh                           NEW — listar automatizaciones con descripción
  apply.sh                          NEW — añadir automatización a config de agente

shell/cron/scheduler.go             MODIFY — añadir Fire(name) para disparo manual en tests
shell/cron/actions.go               MODIFY — pequeñas mejoras si surgen al escribir ejemplos
```

### Patrón pure core / impure shell

- `pkg/` — sin cambios (no hay lógica pura nueva)
- `shell/cron/` — modificación mínima: añadir `Fire(ctx, sc)` para testing manual
- `crons/` — datos puros (YAML + Markdown), sin código Go
- `dev-scripts/cron/` — shell scripts impuros (leen/escriben filesystem, parchean YAML)

### Convención de `crons/<name>/schedule.yaml`

```yaml
# Metadata
name: good-morning
description: "Saludo de buenos días en una sala"

# Schedule por defecto (el agente puede sobreescribir)
default_cron: "0 9 * * *"

# Acción
action:
  kind: send_message            # send_message | llm_prompt
  template: prompts/message.md  # relativo a la carpeta de la automatización

# Sala por defecto (opcional; el agente puede sobreescribir con output_room)
default_output_room: ""
```

Este archivo es solo **documentación + template**. El agente lo referencia en su `config.yaml`
usando la sección `schedules:` habitual; `apply.sh` automatiza ese paso.

## Tareas

### Fase 1: Estructura `crons/` y automatizaciones de ejemplo

- [ ] **1.1** Crear `crons/` con un `README.md` que explique la convención
- [ ] **1.2** Crear `crons/good-morning/schedule.yaml` + `prompts/message.md` (ejemplo `send_message`)
- [ ] **1.3** Crear `crons/daily-summary/schedule.yaml` + `prompts/prompt.md` (ejemplo `llm_prompt`)

### Fase 2: Scripts de gestión en `dev-scripts/cron/`

- [ ] **2.1** `dev-scripts/cron/new.sh` — scaffolder interactivo:
  - Pregunta: nombre, descripción, tipo (`send_message` o `llm_prompt`), cron expression
  - Crea `crons/<name>/schedule.yaml` y el archivo de prompt/mensaje vacío
  - Imprime el bloque YAML listo para copiar en `config.yaml`
- [ ] **2.2** `dev-scripts/cron/list.sh` — lista todas las carpetas bajo `crons/` con nombre y
  descripción extraída del `schedule.yaml`
- [ ] **2.3** `dev-scripts/cron/apply.sh <name> <agent-id>` — añade la entrada `schedules:` a
  `agents/<agent-id>/config.yaml` con los valores por defecto del `schedule.yaml`. Usa `yq` si está
  disponible; en caso contrario imprime el bloque YAML para copiar a mano

### Fase 3: Mejora menor en `shell/cron/`

- [ ] **3.1** Exportar `Fire(ctx context.Context, sc config.ScheduleCfg)` en `scheduler.go` para
  poder disparar un schedule en tests o desde CLI sin esperar al cron
- [ ] **3.2** Actualizar `scheduler_test.go` para usar `Fire` en lugar de `@every 100ms` donde
  sea posible (reduce tiempo de test)

### Fase 4: Tests

- [ ] **4.1** Test de `Fire` para `send_message` inline
- [ ] **4.2** Test de `Fire` para `llm_prompt`
- [ ] **4.3** Verificar que `go test -tags goolm ./shell/cron/...` pasa sin regresiones

### Fase 5: Cleanup y docs

- [ ] **5.1** Añadir entrada `crons/` en la tabla de estructura de `CLAUDE.md`
- [ ] **5.2** Añadir `dev-scripts/cron/` en la misma tabla
- [ ] **5.3** Mención en `dev-scripts/agent/README.md` o crear `dev-scripts/cron/README.md`

---

## Ejemplo de uso

```bash
# Crear una nueva automatización
./dev-scripts/cron/new.sh

# → Nombre de la automatización: weekly-report
# → Descripción: Resumen semanal del equipo
# → Tipo de acción [send_message/llm_prompt]: llm_prompt
# → Cron expression [default: 0 9 * * 1]: 0 9 * * 1
# ✓ Creado: crons/weekly-report/schedule.yaml
# ✓ Creado: crons/weekly-report/prompts/prompt.md
#
# Añade esto a agents/<id>/config.yaml:
#   schedules:
#     - name: weekly-report
#       cron: "0 9 * * 1"
#       output_room: "!ROOM:server.com"
#       action:
#         kind: llm_prompt
#         template: "crons/weekly-report/prompts/prompt.md"

# Listar automatizaciones disponibles
./dev-scripts/cron/list.sh

# → good-morning      send_message   "0 9 * * *"   Saludo de buenos días
# → daily-summary     llm_prompt     "0 18 * * *"  Resumen diario del equipo
# → weekly-report     llm_prompt     "0 9 * * 1"   Resumen semanal del equipo

# Aplicar a un agente (parchea config.yaml automáticamente)
./dev-scripts/cron/apply.sh good-morning assistant-bot
# → Añadido schedule 'good-morning' a agents/assistant-bot/config.yaml
# → Edita output_room en config.yaml para apuntar a la sala correcta
```

## Decisiones de diseño

- **`crons/` como catálogo de datos, no de código**: Los archivos `schedule.yaml` son solo
  documentación + template. No hay un registry Go nuevo; el scheduler sigue leyendo de
  `config.yaml` como hasta ahora. Esto evita añadir un pattern nuevo al proyecto.
- **`apply.sh` opcional**: Si `yq` no está disponible, el script imprime el bloque YAML para
  copiar a mano. Sin dependencias obligatorias.
- **`Fire()` en lugar de cron real en tests**: Los tests actuales usan `@every 100ms` y duermen
  350ms. `Fire()` los hace deterministas e instantáneos.
- **No registry Go para crons**: Añadir un registry compilado (como `cmd/launcher`) para crons
  sería over-engineering. La gestión vía shell scripts es suficiente y más flexible.

## Prerequisitos

- Issue 0005 completado (scheduler en `shell/cron/` — ya está)

## Riesgos

- **`yq` no disponible en el entorno**: `apply.sh` cae back a imprimir el bloque YAML, nunca
  falla. Sin riesgo real.
- **Paths relativos en `schedule.yaml`**: El campo `template` en el YAML es relativo a la raíz
  del proyecto. Documentar claramente en el `README.md` del catálogo.
- **Divergencia entre catálogo y config del agente**: Si alguien edita `schedule.yaml` después
  de aplicarlo, el agente no se actualiza. Es intencional — `apply.sh` es un helper de
  scaffolding, no sync continua.
