feat: v1 — boilerplate WxO + web
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:
149
docs/deployment-guide.md
Normal file
149
docs/deployment-guide.md
Normal file
@@ -0,0 +1,149 @@
|
||||
# Deployment Guide
|
||||
|
||||
Cómo desplegar una solución generada con este template. Cubre Coolify
|
||||
(default FIT) + alternativas.
|
||||
|
||||
## Resumen
|
||||
|
||||
```bash
|
||||
# 1. Tener el .env con las credenciales del tenant WxO y del host público
|
||||
# 2. Tener un Coolify (o un docker host) corriendo
|
||||
# 3. ./scripts/deploy-wxo.sh ← despliega agentes/tools/KBs/connections al tenant
|
||||
# 4. docker compose up -d ← despliega la capa web + mocks (si los hay)
|
||||
# 5. WxO UI → Embed Security OFF (manual, una vez por tenant)
|
||||
# 6. ./evals/smoke-test.sh ← valida end-to-end
|
||||
```
|
||||
|
||||
## Variables de entorno requeridas
|
||||
|
||||
Ver `.env.example` para la lista completa. Las críticas:
|
||||
|
||||
```bash
|
||||
# Tenant WxO
|
||||
ORCHESTRATE_API_URL=https://api.us-south.watson-orchestrate.cloud.ibm.com/instances/<uuid>
|
||||
ORCHESTRATE_API_KEY=<tu-api-key>
|
||||
|
||||
# Para Plan A (webhook a Runs API). Opcional.
|
||||
WATSONX_API_KEY=<api-key-ibm-cloud>
|
||||
IBM_CLOUD_IAM_URL=https://iam.cloud.ibm.com/identity/token
|
||||
WXO_AGENT_ID=<uuid-del-orchestrator-en-live>
|
||||
|
||||
# Host público donde corre tu stack
|
||||
PUBLIC_HOST=mi-cliente.fitlabs.dev
|
||||
```
|
||||
|
||||
## Coolify (FIT default)
|
||||
|
||||
### Crear el stack
|
||||
1. **Coolify panel** → New Resource → Docker Compose
|
||||
2. Connect to git repo (Gitea)
|
||||
3. Build pack: docker compose, path `./docker-compose.yml`
|
||||
4. **Domain**: tu `PUBLIC_HOST` en el servicio que expone la landing/web
|
||||
5. **Env vars**: copiar todos los valores del `.env` al panel de Coolify
|
||||
6. **Deploy**
|
||||
|
||||
### Si Traefik da 503
|
||||
Casi siempre es healthcheck. Verificá:
|
||||
- El healthcheck usa `wget -qO-` o `curl -sf` (no `--spider`) → issue I-008
|
||||
- El endpoint `/health` del servicio responde 200
|
||||
- En logs: `docker logs <container>` busca errores de startup
|
||||
|
||||
### Si sale "TRAEFIK DEFAULT CERT"
|
||||
Tenés labels Traefik manuales en el compose. Borralos. Issue I-009.
|
||||
|
||||
### Redeploy via API
|
||||
```bash
|
||||
curl -X POST "$COOLIFY_API_URL/applications/$COOLIFY_APP_UUID/deploy?force=true" \
|
||||
-H "Authorization: Bearer $COOLIFY_API_TOKEN"
|
||||
```
|
||||
|
||||
## Docker Compose local
|
||||
|
||||
Para development. Trae el override `docker-compose.local.yml` que agrega
|
||||
ports + bridge network.
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
LANDING_PORT=18900 docker compose \
|
||||
-f docker-compose.yml \
|
||||
-f docker-compose.local.yml \
|
||||
up -d --build
|
||||
```
|
||||
|
||||
URLs:
|
||||
- Landing: `http://localhost:18900/`
|
||||
- Web layer: `http://localhost:18900/web/`
|
||||
- Cualquier mock: `http://localhost:18900/<mock-name>/`
|
||||
|
||||
## Otros targets (K8s, Cloud Run, etc.)
|
||||
|
||||
El template es Docker-compose-first, pero los servicios son containers
|
||||
estándar. Para migrar:
|
||||
|
||||
1. **Kubernetes**: convertir cada service del compose en `Deployment` +
|
||||
`Service`. Usar un Ingress controller para el routing (estilo Traefik).
|
||||
`kompose convert` te da una primera versión.
|
||||
2. **Cloud Run**: cada service va por separado. Las connections entre
|
||||
ellos por URLs HTTP públicas o VPC connector.
|
||||
3. **ECS Fargate**: task definition por service. ALB para el routing.
|
||||
|
||||
El **WxO deploy (`./scripts/deploy-wxo.sh`) es independiente del target**.
|
||||
Lo que cambia es solo el host público que el ADK ve en las connections.
|
||||
|
||||
## Deploy del WxO stack
|
||||
|
||||
`./scripts/deploy-wxo.sh` es idempotente. Hace:
|
||||
|
||||
1. Connections en **draft y live** (issue I-004)
|
||||
2. Tools import (Python + OpenAPI según haya)
|
||||
3. KBs import
|
||||
4. Agents import (specialists primero, orchestrator último)
|
||||
5. Agents deploy a live
|
||||
6. Channel creation
|
||||
|
||||
Lo podés re-correr todas las veces que quieras.
|
||||
|
||||
### Variables que afecta el script
|
||||
|
||||
| Var | Default | Para qué |
|
||||
|---|---|---|
|
||||
| `PUBLIC_HOST` | `mi-cliente.fitlabs.dev` | Base URL de las connections |
|
||||
| `WXO_ENV_NAME` | `default` | Cuál env del ADK usar |
|
||||
| `SKIP_TOOLS` | `false` | Saltar la fase de tools (útil si solo cambiaste agentes) |
|
||||
| `SKIP_KB` | `false` | Saltar KBs (idem) |
|
||||
|
||||
## Capturar IDs después del deploy
|
||||
|
||||
```bash
|
||||
orchestrate agents list
|
||||
# Buscá: mesa_n1 (o como se llame tu orchestrator)
|
||||
# y su row con env=live
|
||||
# Capturá: agent_id + env_id
|
||||
```
|
||||
|
||||
Esos dos UUIDs van a:
|
||||
- `web/.../index.html` → `agentId` + `agentEnvironmentId` del widget de chat
|
||||
- `.env` → `WXO_AGENT_ID` (para Plan A webhook)
|
||||
- Coolify env vars
|
||||
|
||||
## Paso manual obligatorio — Embed Security OFF
|
||||
|
||||
> WxO Console → Settings → Embed Security → **Off**
|
||||
|
||||
Sin esto el embed se queda en "Cargando agente...". Issue I-007.
|
||||
|
||||
## Smoke test
|
||||
|
||||
```bash
|
||||
./evals/smoke-test.sh
|
||||
```
|
||||
|
||||
Hace login → crea un caso → ejecuta → polea → assert. Si pasa, el deploy
|
||||
está OK.
|
||||
|
||||
## Si algo falla
|
||||
|
||||
1. `./evals/direct-backend-probe.sh` — aísla auth/connection de logic
|
||||
2. `./scripts/check-adk-version.sh` — confirma que el ADK pinneado todavía es válido
|
||||
3. `docs/known-issues.md` — los 16 errores conocidos con su fix
|
||||
4. `docs/RUNBOOK.md` — operaciones de recovery
|
||||
Reference in New Issue
Block a user