# Architecture Patterns Árbol de decisión que usa el subagente `wxo-architect` cuando arrancás un caso nuevo. Te llevo pregunta por pregunta. --- ## Pregunta 1 — ¿Cuántos dominios distintos toca el caso? Un "dominio" = una superficie funcional bien delimitada (identidad, operaciones, RRHH, finanzas, CRM, etc.). - **0–1 dominio** → 1 agente solo. Salí del árbol con la **Topología Single**. - **2–5 dominios** → N specialists + 1 orchestrator. **Topología Multi-Specialist** (estilo Cotemar). - **6+ dominios** → 2 capas: sub-orchestrators temáticos. **Topología Multi-Capa**. --- ## Pregunta 2 — ¿El flujo es lineal o ramificado? - **Lineal y conocido** (caso entra → A → B → C → D → resultado, siempre el mismo orden): aplicá **Patrón Meta-Tool** (estilo Dun). Una sola tool `run_full_case` que el backend orquesta internamente. El agente invoca esa tool y listo. - **Ramificado** (el agente decide qué hacer según el input): N tools individuales, agente razona. Cuidado con `recursion_limit=30` (ver `known-issues.md`). - **Mixto**: parte lineal en meta-tool, parte ramificada en tools individuales. Es lo más común en casos reales. --- ## Pregunta 3 — ¿Cada agente necesita razonar sobre procedimientos escritos? Para cada agente, preguntate: "¿el LLM necesita citar un runbook para decidir bien?" - **Sí** (procedural): este agente tiene **KB con runbooks**. Estilo Cotemar AD specialist. - **No** (API-driven): este agente **no tiene KB**. El system prompt describe qué hace, las tools describen las acciones disponibles. Estilo Dun QA Studio. - **Mixto**: KB para el "qué" + tools para el "cómo". Solo cuando los procedimientos son largos y variables. --- ## Pregunta 4 — ¿Qué tipo de tools va a tener cada agente? Por cada dominio, elegí el tipo de tool: ### Opción A — OpenAPI (preferido si tenés backend propio) **Cuándo:** tu solución incluye un backend (FastAPI, Express, lo que sea) que ya define endpoints REST. **Pros:** - Una sola fuente de verdad (el spec) - ADK importa todo en un comando - Cambios al backend = re-import del spec, no toques YAML de tool **Pattern del template (estilo Dun):** - Backend expone `/orchestrate-tools-spec.json` (endpoint filtrado) - Filtra el openapi.json a una allowlist `PUBLIC_TOOLS` - Fuerza `description` y `security` per-operation - Patch del `servers[0].url` en deploy time según env Ver `wxo/tools/openapi/_backend_filter_endpoint.py` para el template. ### Opción B — Python `@tool` (preferido para mocks/PoC) **Cuándo:** estás prototipando, mocks externos, lógica simple por tool, sin backend que valga la pena mantener. **Pros:** - Rápido de escribir, una función = una tool - Fácil de testear con pytest - Bajo overhead **Pattern del template (estilo Cotemar):** - Una función `@observable_tool(name="x")` por endpoint mockeado - Lee `BASE_URL` del environment de su connection - `requests.post(...)` y devuelve dict - `_compat.py` inline al inicio del archivo Ver `wxo/tools/python/_template_tools.py`. ### Opción C — MCP (preferido si el sistema lo expone) **Cuándo:** el sistema externo (HubSpot, Outline, una DB con MCP server, GitHub vía MCP, etc.) ya expone un MCP server. **Pros:** - Trae types + permisos del sistema - Mantenido por el vendor - Una sola connection MCP da acceso a todas las tools del server **Pattern del template:** - Una `connection.yaml` de tipo MCP apuntando al server - ADK descubre las tools y las hace disponibles al agente - Ver `wxo/tools/mcp/_template_mcp_connection.yaml` ### Decisión | Situación | Recomendación | |---|---| | Es PoC, mocks externos | Python @tool | | Tengo backend propio (FastAPI/Express) | OpenAPI | | Conecto a SaaS con MCP server | MCP | | Conecto a SaaS sin MCP server | OpenAPI (escribís el spec a mano) o Python | | Mezcla | Cada agente puede usar más de uno | --- ## Pregunta 5 — ¿Web layer: cuál stack? Dos happy-paths probados: ### Stack A — FastAPI + HTMX + Jinja (default) **Cuándo:** demos, PoCs, control planes, kanbans, paneles operativos **Pros:** SSR, sin build step, polling con `hx-trigger` es trivial, una sola persona la mantiene **Contras:** menos interactivo, menos componibilidad **Origen:** estilo Cotemar (UNUS Kanban + Control Plane) ### Stack B — FastAPI + React + Vite + Tailwind + zustand **Cuándo:** app productiva con varios usuarios, mucha interacción, UI rica **Pros:** ecosistema React, lazy loading, state management decente **Contras:** build step, más superficie de mantenimiento **Origen:** estilo Dun (QA Studio) ### Decisión - **Demo / interno / PoC** → Stack A - **Producción / multi-usuario / app rica** → Stack B - **Híbrido** → Stack A para dashboards, Stack B para la app principal, unidos por reverse proxy El template trae Stack A en `web/_default_fastapi_htmx/`. Stack B viene documentado pero no implementado (el subagente Claude `web-layer-builder` te lo arma según el caso). --- ## Pregunta 6 — ¿Deploy: dónde corre esto? Tres opciones soportadas: | Target | Para qué | Ver | |---|---|---| | **Coolify** (FIT default) | Demos + PoCs productivos en `*.fitlabs.dev` | `docs/deployment-guide.md` | | **Docker compose local** | Dev / testing | `docs/INSTRUCCIONES.md` | | **K8s / Cloud Run / otro** | Producción del cliente | `docs/deployment-guide.md` § "Other targets" | --- ## Topologías resultantes ### Topología Single (1 agente) ``` [user] → [agente único] ──tools──→ [sistema externo] └──KB──→ [opcional] ``` ### Topología Multi-Specialist (Cotemar pattern) ``` ┌──→ ad_specialist ──tools──→ AD [user] → [N1] ────┼──→ ops_specialist ──tools──→ Ops (orch) └──→ rrhh_specialist ──tools──→ HR │ └─escalate→ runbook 03 (KB propia) ``` ### Topología Meta-Tool (Dun pattern) ``` [user] → [agente único] ──run_full_case(id)──→ [backend orquesta: step 1, step 2, ... write_audit cada paso] ``` ### Topología Multi-Capa (>5 dominios) ``` ┌─→ [sub-orch identidad] ─→ ad, hr, vendors [user] → [super-orch] ────┤ ├─→ [sub-orch ops] ─→ dynatrace, k8s, db └─→ [sub-orch finanzas] ─→ sap, billing ``` --- ## Cuando dudes - **¿1 agente o varios?** → Si los dominios son disjuntos, varios. Si todo es del mismo dominio, uno. - **¿KB o no?** → Si hay procedimiento escrito que el LLM debe seguir literal, sí. Si no, no. - **¿OpenAPI o Python?** → ¿Tenés backend? OpenAPI. ¿Mocks? Python. - **¿Meta-tool o tools sueltas?** → ¿El flujo es lineal y conocido? Meta-tool. ¿El agente decide? Sueltas. Cuando dudes, **arrancá con menos**. Es más fácil splittear un agente en dos que mergear dos en uno.