feat: v1 — boilerplate WxO + web
Some checks failed
CI — Lint + Evals / lint (push) Has been cancelled
CI — Lint + Evals / smoke (push) Has been cancelled

Boilerplate completo para construir soluciones agénticas sobre IBM
watsonx Orchestrate (ADK 2.x) con una capa web encima.

Destilado de cotemar-poc-n1 y dun-casos-prueba. Incluye:

- 11 docs (best practices, architecture patterns, ADK cheatsheet,
  observability, tool authoring, deployment, RUNBOOK, DEPLOY_TO_NEW_WOX,
  known-issues con 16 errores reales y fix, eval strategy, INDEX)
- 13 templates WxO (orchestrator/specialist/single-meta agents,
  3 connections, KB + runbook, observable_tool decorator, coercion
  helpers, Python tools, OpenAPI spec, backend filter endpoint, webhook
  validator HMAC, MCP connection)
- 6 scripts (deploy idempotente con fallback ADK, undeploy, reset,
  check-adk-version, new-specialist scaffold, eval-agents runner)
- 4 eval pieces (linter de best practices, runner, smoke-test, direct
  backend probe) + scenario templates
- 8 subagentes Claude (.claude/agents/) — wxo-architect, wxo-agent-author,
  wxo-tool-author, runbook-author, mock-builder, backend-tool-builder,
  eval-author, web-layer-builder
- Skill bundle fit-wxo-bootstrap/ (SKILL.md + 3 templates) listo para
  copiar a ~/.claude/skills/
- Web layer default FastAPI+HTMX con vista timeline observable + endpoint
  receptor de trazas
- Docker compose Coolify-ready (healthcheck wget -qO-, sin labels Traefik,
  network split internal:true)
- CI Gitea workflow con lint + smoke

Best practices enforced por evals/lint_wxo_yaml.py:
- A1: máx 10 tools por agente
- A3: orchestrator sin tools de remediación
- A6: agente sin propósito (react sin tools ni KB)
- T1: @observable_tool obligatorio, no @tool directo
- T3: _compat shim inline en tools.py
- D1: docker-compose sin wget --spider
- I-005: OpenAPI con description per-operation
- I-009: sin labels Traefik manuales

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Felipe Arentsen
2026-05-16 14:59:44 +00:00
commit b089c2ef18
70 changed files with 6739 additions and 0 deletions

178
docs/RUNBOOK.md Normal file
View File

@@ -0,0 +1,178 @@
# RUNBOOK — Operaciones
Cómo monitorear, recuperar, rotar y troubleshootear una solución
desplegada con este template.
## URLs y endpoints clave
| URL | Para qué |
|---|---|
| `https://$PUBLIC_HOST/` | Landing con chat embed |
| `https://$PUBLIC_HOST/web/` | App principal (UI) |
| `https://$PUBLIC_HOST/health` | Healthcheck (200 = todo OK) |
| `https://$PUBLIC_HOST/api/traces` | Vista timeline de tool calls (admin) |
| WxO Console | Settings, agents, channels |
| Coolify panel | Deploy, logs, env vars |
## Monitoring
### Healthcheck simple
```bash
curl -sf "https://$PUBLIC_HOST/health" && echo OK || echo FAIL
```
### Smoke test nightly
Configurar CI/cron que corra cada noche:
```bash
./evals/smoke-test.sh
```
Si falla, alerta por email/Slack.
### Logs en tiempo real
```bash
# Local
docker compose logs -f --tail=100
# Coolify
# Panel → app → Logs tab
```
Buscar:
- `ERROR` o `Exception` en stdout
- `recursion_limit` (issue I-001)
- `kid not found` (issue I-004)
- `422 Unprocessable Entity` (issue I-003)
## Recovery procedures
### El chat embed quedó en "Cargando..."
1. Settings → Embed Security debe estar **Off**. Issue I-007.
2. Verificar que el `agentId` y `agentEnvironmentId` del HTML
coincidan con `orchestrate agents list --env live`.
3. Browser console: buscar errores CORS o 401.
### Casos atascados en `executing` (issue I-012)
El watchdog del backend los promueve a `paused` automáticamente
después de 90s. Si no pasa:
1. Ver logs: `grep "case_id=XXXX"`
2. Si Orchestrate jamás llamó al callback, el run murió: re-trigger desde la UI
3. Si el callback llegó pero la DB no actualizó, ver issue I-013
### El agente printea tool calls como texto (issue I-002)
1. Verificar `llm:` en el YAML del agente = `groq/openai/gpt-oss-120b`
2. Verificar que REGLA #0 está en el prompt
3. Si persiste con gpt-oss-120b → reportar a IBM, es regresión del modelo
### Pydantic 422 en tool calls (issue I-003)
1. Ver el payload exacto que el LLM mandó (logs del backend)
2. Si stringificó algo que debería ser int/list → falta `@field_validator(mode="before")`
3. Agregar el validator, redeployar el backend
### Deploy WxO falla con `kid not found` (issue I-004)
```bash
# Re-configurar la connection en live
orchestrate connections configure -a <app_id> --env live --type team --kind <kind>
orchestrate connections set-credentials -a <app_id> --env live -e "BASE_URL=..."
# Re-deployar agente
orchestrate agents deploy --name <agent> --env live
```
### Coolify dio 503 después de redeploy (issue I-008)
1. `docker logs <container>` → buscar healthcheck failures
2. Cambiar `wget --spider` a `wget -qO-` en el Dockerfile
3. Rebuild
### Backend OK pero WxO no llega (issue I-008/I-009)
```bash
# Probar desde fuera
curl -sf "https://$PUBLIC_HOST/api/v1/health"
# Si 200 OK pero WxO da timeout → firewall/network
# Si 503 → Traefik/healthcheck
# Si TRAEFIK DEFAULT CERT → labels manuales, ver I-009
```
## Rotación de secretos
### API key del tenant WxO
1. WxO Console → IAM → Generate new API key
2. Actualizar `.env`: `ORCHESTRATE_API_KEY=<nuevo>`
3. `docker compose up -d --force-recreate` (NO `restart`, issue I-011)
4. `orchestrate env activate <env-name>` con el nuevo key
### Credenciales de connection
```bash
orchestrate connections set-credentials -a <app_id> --env draft -e "BASE_URL=..." -e "API_KEY=<nuevo>"
orchestrate connections set-credentials -a <app_id> --env live -e "BASE_URL=..." -e "API_KEY=<nuevo>"
```
No hay que re-deployar agentes — las connections se resuelven en runtime.
### Webhook signing secret
1. Generar nuevo secret
2. Actualizar `.env` + Coolify env vars: `WEBHOOK_SECRET=<nuevo>`
3. `--force-recreate`
4. Si el sistema externo usa el viejo secret, coordinar el switch
## Backup y restore
### Backup
- **Código + YAMLs**: vive en Gitea. Backup automático del repo.
- **Backend DB**: `docker exec <db-container> pg_dump > backup.sql` (o equivalente)
- **Audit logs**: parte del backup de la DB
- **Trazas SQLite**: `cp web/data/traces.db backup/`
- **WxO config**: los YAMLs del repo. `orchestrate agents list` te dice qué está en live.
### Restore
- **Código**: `git clone` y `./scripts/deploy-wxo.sh`
- **DB**: `pg_restore < backup.sql`
- **Traces**: si las perdés, no es crítico (son observabilidad histórica)
### Disaster recovery completo
1. Clonar repo en nuevo host
2. `.env` con credenciales del tenant (las que ya tenías guardadas)
3. `./scripts/deploy-wxo.sh` — recrea todo en WxO desde los YAMLs
4. `docker compose up -d` — levanta backend/web
5. Restore DB si necesario
6. Capturar nuevos IDs, propagar
7. Smoke test
Tiempo objetivo: <30 min.
## Troubleshooting checklist
Cuando algo se rompe y no sabés por dónde empezar:
1. [ ] `curl -sf $PUBLIC_HOST/health` — ¿el servicio responde?
2. [ ] `docker ps` — ¿los containers están healthy?
3. [ ] `docker logs <container> --tail=200` — ¿hay errores recientes?
4. [ ] `orchestrate agents list` — ¿el agente está en live?
5. [ ] `./evals/direct-backend-probe.sh` — ¿la auth funciona?
6. [ ] `./evals/smoke-test.sh` — ¿el flujo end-to-end?
7. [ ] WxO Console → Runs → últimos runs — ¿qué error tienen?
8. [ ] `docs/known-issues.md` — ¿coincide con algún I-XXX?
Si después de los 8 sigue roto, escalalo. Pero el 90% de los problemas
están en uno de los 8.
## Versión / actualización del ADK
```bash
./scripts/check-adk-version.sh
```
Si hay nueva versión:
1. **NO actualizar directamente.**
2. Crear branch `chore/adk-X.Y.Z`
3. `pip install ibm-watsonx-orchestrate==X.Y.Z`
4. Re-deployar a un env de staging
5. Correr todas las evals
6. Si pasan, PR + merge + deploy a prod
7. Actualizar el pin en `requirements.txt` + `check-adk-version.sh`
## Cuando todo lo demás falla
Ver `docs/known-issues.md` y `docs/adk-2x-cheatsheet.md`. Si tampoco
está ahí, abrir issue en el repo del template para que la próxima
persona no lo sufra.