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:
168
skill/fit-wxo-bootstrap/SKILL.md
Normal file
168
skill/fit-wxo-bootstrap/SKILL.md
Normal file
@@ -0,0 +1,168 @@
|
||||
---
|
||||
name: fit-wxo-bootstrap
|
||||
description: Genera una solución completa basada en fit-boilerplate-wox para un cliente o caso de uso nuevo. Conversa para entender el caso, decide la topología WxO (cuántos agentes, qué dominios, qué tipo de tools, qué stack web), y dispara subagentes Claude en paralelo que escriben agentes, tools, runbooks, mocks, evals y la capa web. Triggers — usá este skill cuando el usuario diga "quiero arrancar una solución WxO nueva", "armá un proyecto desde el boilerplate", "necesito generar agentes para [cliente]", "bootstrap WxO", "fit-boilerplate", o cualquier variación de bootstrappear una solución agéntica sobre watsonx Orchestrate.
|
||||
---
|
||||
|
||||
# fit-wxo-bootstrap
|
||||
|
||||
Skill conversacional para arrancar una nueva solución agéntica sobre
|
||||
**watsonx Orchestrate (ADK 2.x)** usando `fit-boilerplate-wox` como base.
|
||||
|
||||
Es el complemento del boilerplate: el repo trae las plantillas y subagentes,
|
||||
y esta skill orquesta la conversación con el usuario y el lanzamiento
|
||||
paralelo de subagentes para construir la solución.
|
||||
|
||||
## Cuándo se invoca
|
||||
|
||||
- "Quiero arrancar una solución WxO nueva para [cliente]"
|
||||
- "Bootstrap el boilerplate para [caso de uso]"
|
||||
- "Armá los agentes para [descripción]"
|
||||
- "Necesito generar el esqueleto WxO para [cliente]"
|
||||
|
||||
## Flujo de la skill
|
||||
|
||||
### Fase 1 — Entender el caso
|
||||
|
||||
Pregunto al usuario:
|
||||
|
||||
1. **¿Qué cliente / caso de uso?**
|
||||
- Si es un cliente FIT existente, sugerirle usar las skills hermanas
|
||||
`prep-reunion` o `consulta-fichas` para traer contexto.
|
||||
- Si es un caso de uso ya conocido, capturar el contexto en una nota.
|
||||
|
||||
2. **¿Tenés contexto adicional para compartir?** (transcripción, email,
|
||||
licitación, dibujo de arquitectura, etc.)
|
||||
- Si sí, leerlo y resumirlo.
|
||||
- Si no, seguir.
|
||||
|
||||
3. **Dominios identificados** — listar los que YO veo y pedir confirmación.
|
||||
|
||||
### Fase 2 — Decidir topología (con `wxo-architect`)
|
||||
|
||||
Llamar al subagente `wxo-architect` (de `.claude/agents/wxo-architect.md`
|
||||
del boilerplate) pasándole la descripción del caso. Recibir su propuesta
|
||||
de:
|
||||
- Topología (Single / Multi-Specialist / Meta-Tool / Multi-Capa)
|
||||
- Agentes con nombre + tools + KB sí/no + collaborators
|
||||
- Tipo de tools por dominio (Python / OpenAPI / MCP)
|
||||
- Stack web sugerido
|
||||
- Runbooks a escribir
|
||||
- Evals scenarios mínimos
|
||||
|
||||
**Mostrarle al usuario la propuesta completa** y pedir confirmación o
|
||||
ajustes. Iterar hasta que apruebe.
|
||||
|
||||
### Fase 3 — Clonar el boilerplate
|
||||
|
||||
```bash
|
||||
git clone https://gitea.fitlabs.dev/farentsen/fit-boilerplate-wox.git <cliente>
|
||||
cd <cliente>
|
||||
rm -rf .git && git init
|
||||
```
|
||||
|
||||
Personalizar:
|
||||
- `README.md` con el nombre del cliente / caso
|
||||
- `.env.example` con los placeholders correctos
|
||||
- Borrar las plantillas REPLACE_* que NO se van a usar
|
||||
|
||||
### Fase 4 — Dispatch paralelo de subagentes
|
||||
|
||||
Lanzar EN UN SOLO MENSAJE (paralelo) los subagentes que correspondan
|
||||
según la topología aprobada:
|
||||
|
||||
- **1 instancia de `wxo-agent-author`** por cada agente (orchestrator + N specialists)
|
||||
- **1 instancia de `wxo-tool-author`** por cada dominio (con type Python/OpenAPI/MCP según corresponda)
|
||||
- **1 instancia de `runbook-author`** por cada runbook
|
||||
- **1 instancia de `mock-builder`** por cada sistema externo a mockear
|
||||
- **1 instancia de `backend-tool-builder`** si la solución tiene backend propio
|
||||
- **1 instancia de `eval-author`** por cada scenario de eval planificado
|
||||
- **1 instancia de `web-layer-builder`** para la capa web (modo A o B según se decidió)
|
||||
|
||||
Cada subagente devuelve el archivo correspondiente. Mientras corren,
|
||||
informar al usuario el progreso.
|
||||
|
||||
### Fase 5 — Validación
|
||||
|
||||
Una vez que todos terminaron:
|
||||
1. Correr `python3 evals/lint_wxo_yaml.py` — debe pasar
|
||||
2. Correr `./scripts/check-adk-version.sh`
|
||||
3. Revisar visualmente la estructura final con `tree -L 3`
|
||||
4. Mostrar al usuario lo que se generó
|
||||
|
||||
### Fase 6 — Recomendaciones finales
|
||||
|
||||
Invocar `claude-code-setup:claude-automation-recommender` sobre el repo
|
||||
recién generado para sugerir hooks y agentes extra específicos del proyecto.
|
||||
|
||||
Si hay cambios significativos, invocar `code-review:code-review` antes
|
||||
del commit inicial.
|
||||
|
||||
### Fase 7 — Commit inicial + instrucciones de deploy
|
||||
|
||||
```bash
|
||||
git add . && git commit -m "feat: bootstrap from fit-boilerplate-wox
|
||||
|
||||
Cliente: <X>
|
||||
Topología: <Y>
|
||||
Agentes: <lista>
|
||||
Generado con fit-wxo-bootstrap skill."
|
||||
```
|
||||
|
||||
Mostrar al usuario los **pasos manuales restantes**:
|
||||
|
||||
1. `cp .env.example .env` y rellenar
|
||||
2. `python3.12 -m venv .venv-wxo && source .venv-wxo/bin/activate`
|
||||
3. `pip install ibm-watsonx-orchestrate==2.1.0`
|
||||
4. `orchestrate env add ... && orchestrate env activate ...`
|
||||
5. `./scripts/deploy-wxo.sh`
|
||||
6. Capturar IDs del orchestrator (live env)
|
||||
7. Pegar IDs en `web/.../index.html` + `.env`
|
||||
8. WxO Console → Embed Security OFF
|
||||
9. `./evals/smoke-test.sh`
|
||||
|
||||
## Buenas prácticas que la skill enforce
|
||||
|
||||
Heredadas de `docs/wxo-best-practices.md` del boilerplate:
|
||||
|
||||
1. **Máx 10 tools por agente.** Si la propuesta del `wxo-architect`
|
||||
tiene un agente con >10 tools, parar y pedir split.
|
||||
2. **Domain specialists, no todistas.** Si veo agentes que mezclan
|
||||
dominios, separar.
|
||||
3. **Orchestrator nunca remedia.** Tools del orchestrator: solo ticketing
|
||||
+ escalación.
|
||||
4. **KB es opcional.** No forzar KB en agentes API-driven.
|
||||
5. **Conexiones en draft Y live.**
|
||||
6. **OpenAPI con description + security per-op.**
|
||||
7. **Tools observables por default** (`@observable_tool`, no `@tool` directo).
|
||||
8. **Coerción Pydantic** en todo input model.
|
||||
|
||||
## Skills hermanas que esta skill puede invocar
|
||||
|
||||
- `prep-reunion` — si el cliente ya existe en Outline/HubSpot
|
||||
- `consulta-fichas` — para traer experiencia previa con tecnologías similares
|
||||
- `fit-analisis-inicial` — si vale la pena armar un deck cliente-facing antes de codear
|
||||
- `claude-code-setup:claude-automation-recommender` — sugerir automations al final
|
||||
- `code-review:code-review` — review del esqueleto generado
|
||||
- `feature-dev:feature-dev` — para agregar features después del bootstrap
|
||||
|
||||
## Templates incluidos en la skill
|
||||
|
||||
Ver `templates/` en este directorio:
|
||||
- `templates/conversation-guide.md` — ejemplo de cómo guiar la conversación
|
||||
- `templates/architect-prompt-template.md` — qué pasarle al subagente architect
|
||||
- `templates/parallel-dispatch.md` — cómo lanzar todos los subagentes en paralelo
|
||||
|
||||
## Cuando NO usar esta skill
|
||||
|
||||
- Si el usuario quiere modificar una solución existente → usar `feature-dev`
|
||||
- Si el usuario quiere debuggear un problema → usar `general-purpose` + `docs/known-issues.md`
|
||||
- Si el usuario quiere review de código → usar `code-review`
|
||||
|
||||
## Output esperado
|
||||
|
||||
Al terminar, el usuario tiene:
|
||||
- Un repo local `<cliente>/` listo para commitear a Gitea
|
||||
- Todos los YAMLs, tools, runbooks, mocks, evals, web generados
|
||||
- Pasos manuales de deploy claramente listados
|
||||
- Un agente orquestador + N especialistas listos para `orchestrate ... import`
|
||||
- Un linter que ya pasa
|
||||
@@ -0,0 +1,56 @@
|
||||
# Prompt template — invocar el subagente `wxo-architect`
|
||||
|
||||
Cuando llamás al subagente `wxo-architect` (definido en `.claude/agents/wxo-architect.md`
|
||||
del boilerplate clonado), usá este formato:
|
||||
|
||||
```
|
||||
Sos el wxo-architect. Necesito que decidas la topología WxO para esta solución:
|
||||
|
||||
CASO DE USO:
|
||||
[descripción completa de lo que el usuario te contó]
|
||||
|
||||
CLIENTE: [nombre]
|
||||
|
||||
CONTEXTO ADICIONAL:
|
||||
[transcripción, RFP, email, etc. — pegar literal]
|
||||
|
||||
DOMINIOS IDENTIFICADOS POR EL USUARIO:
|
||||
1. [dominio 1]
|
||||
2. [dominio 2]
|
||||
...
|
||||
|
||||
SISTEMAS EXTERNOS:
|
||||
- [sistema A]: [tipo: mock | backend propio | SaaS con MCP | API existente]
|
||||
- [sistema B]: ...
|
||||
|
||||
STACK WEB ELEGIDO: [FastAPI+HTMX | FastAPI+React]
|
||||
|
||||
OUTPUT:
|
||||
Devolveme un documento markdown con todas las secciones del template de tu agente:
|
||||
1. Resumen del caso
|
||||
2. Dominios
|
||||
3. Topología propuesta (Single | Multi-Specialist | Meta-Tool | Multi-Capa)
|
||||
4. Agentes detallados (nombre, propósito, tools, KB, collaborators)
|
||||
5. Tipo de tools por dominio
|
||||
6. Sistemas externos y cómo se integran
|
||||
7. Web layer
|
||||
8. Runbooks a escribir
|
||||
9. Evals scenarios mínimos
|
||||
10. Riesgos / decisiones abiertas
|
||||
|
||||
APLICÁ ESTRICTAMENTE las reglas de docs/wxo-best-practices.md:
|
||||
- Máx 10 tools por agente
|
||||
- Domain specialists, no todistas
|
||||
- Orchestrator nunca remedia
|
||||
- KB opcional
|
||||
- Patrón meta-tool si el flujo es lineal
|
||||
```
|
||||
|
||||
## Iteración
|
||||
|
||||
Cuando el `wxo-architect` devuelva su propuesta:
|
||||
1. Leelo entero
|
||||
2. Mostrale al usuario
|
||||
3. Pediles confirmación O ajustes
|
||||
4. Si hay ajustes, volvés a invocar `wxo-architect` con los cambios
|
||||
5. Cuando el usuario aprueba, pasamos a la Fase 4 (dispatch paralelo)
|
||||
73
skill/fit-wxo-bootstrap/templates/conversation-guide.md
Normal file
73
skill/fit-wxo-bootstrap/templates/conversation-guide.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# Guía conversacional
|
||||
|
||||
Cómo guiar la conversación con el usuario en la Fase 1 de la skill.
|
||||
|
||||
## Apertura
|
||||
|
||||
> "Genial, vamos a arrancar una solución WxO nueva. Primero necesito
|
||||
> entender el caso. ¿Para qué cliente o caso de uso es?"
|
||||
|
||||
## Preguntas en cascada
|
||||
|
||||
### 1. Cliente / Caso
|
||||
|
||||
- **Si menciona un cliente FIT existente:**
|
||||
> "¿Querés que traiga contexto de la ficha del cliente en Outline y
|
||||
> deals activos de HubSpot? Puedo invocar la skill `consulta-fichas`."
|
||||
|
||||
- **Si menciona un caso de uso técnico ("mesa N1", "QA testing", etc.):**
|
||||
> "Ok, ¿es similar a alguno que hayamos hecho? (Cotemar = mesa N1, Dun
|
||||
> = QA copilot). Si tenés transcripción, email, RFP o diagrama, mandalo."
|
||||
|
||||
- **Si es vago:**
|
||||
> "Para diseñar la arquitectura necesito saber: (a) qué le pide el usuario
|
||||
> al agente, (b) qué sistemas externos necesita tocar, (c) qué procedimiento
|
||||
> debe seguir. Si tenés un caso concreto, contámelo paso a paso."
|
||||
|
||||
### 2. Dominios
|
||||
|
||||
Después de oír el caso, decir lo que vos VES:
|
||||
|
||||
> "Por lo que me contás identifico estos dominios:
|
||||
> 1. **[X]** — porque mencionaste [evidencia]
|
||||
> 2. **[Y]** — porque [evidencia]
|
||||
>
|
||||
> ¿Falta alguno? ¿Alguno sobra?"
|
||||
|
||||
### 3. Sistemas externos
|
||||
|
||||
> "Qué sistemas tocaría cada dominio?
|
||||
> - ¿Son sistemas reales (AD, ServiceNow, SAP, Dynatrace) que ya existen?
|
||||
> - ¿O vamos a mockear todo para un PoC?
|
||||
> - ¿Hay backend propio que ya tenemos que extender?"
|
||||
|
||||
### 4. Stack web
|
||||
|
||||
> "Para la capa web hay dos happy-paths:
|
||||
> - **FastAPI + HTMX (SSR)** — perfecto para demos, control planes, paneles operativos
|
||||
> - **FastAPI + React + Vite** — para apps productivas con varios usuarios
|
||||
>
|
||||
> ¿Cuál te encaja?"
|
||||
|
||||
### 5. Confirmación
|
||||
|
||||
Antes de empezar a generar:
|
||||
|
||||
> "Resumiendo:
|
||||
> - Cliente: X
|
||||
> - Topología: 1 orchestrator + N specialists
|
||||
> - Agentes: [lista con nombres]
|
||||
> - Tools: [Python para mocks, OpenAPI para backend Y]
|
||||
> - Web: HTMX
|
||||
> - Runbooks: [lista]
|
||||
>
|
||||
> ¿Avanzo con esto? ¿Querés cambiar algo?"
|
||||
|
||||
## Cuándo NO seguir
|
||||
|
||||
Detenerse y pedir más contexto si:
|
||||
- No queda claro qué le pide el usuario al agente
|
||||
- No queda claro qué sistemas externos hay
|
||||
- La topología propuesta tiene un agente con >10 tools (split)
|
||||
- El orchestrator necesitaría tools de remediación (rediseñar)
|
||||
- Hay >5 dominios y el usuario no quiere multi-capa (advertir consecuencias)
|
||||
171
skill/fit-wxo-bootstrap/templates/parallel-dispatch.md
Normal file
171
skill/fit-wxo-bootstrap/templates/parallel-dispatch.md
Normal file
@@ -0,0 +1,171 @@
|
||||
# Dispatch paralelo de subagentes
|
||||
|
||||
Cuando la topología está aprobada (Fase 4), lanzá TODOS los subagentes
|
||||
en paralelo (un único mensaje con múltiples `Agent` tool calls).
|
||||
|
||||
## Patrón
|
||||
|
||||
```
|
||||
Voy a lanzar N subagentes en paralelo para construir toda la solución.
|
||||
Cada uno escribe su pieza. Esto va a tomar 2-5 minutos.
|
||||
```
|
||||
|
||||
Luego invocá EN UN SOLO MENSAJE algo así:
|
||||
|
||||
```python
|
||||
# Pseudocódigo — el agente principal hace múltiples llamadas Agent() en paralelo
|
||||
|
||||
# Por cada agente WxO en la topología:
|
||||
for agent in topology.agents:
|
||||
Agent(
|
||||
description=f"Write WxO agent YAML for {agent.name}",
|
||||
subagent_type="wxo-agent-author",
|
||||
prompt=f"""
|
||||
Escribí el agent.yaml de WxO para:
|
||||
|
||||
role: {agent.role}
|
||||
name: {agent.name}
|
||||
display_name: "{agent.display_name}"
|
||||
description: {agent.description}
|
||||
domain: {agent.domain}
|
||||
tools: {agent.tools}
|
||||
collaborators: {agent.collaborators}
|
||||
knowledge_base: {agent.kb or "none"}
|
||||
client_name: {client}
|
||||
business_context: {agent.business_context}
|
||||
escalation_table: {agent.escalation_table or "none"}
|
||||
examples: {agent.examples}
|
||||
|
||||
Guardalo en wxo/agents/{agent.name}.agent.yaml
|
||||
Aplicá todas las reglas de docs/wxo-best-practices.md.
|
||||
"""
|
||||
)
|
||||
|
||||
# Por cada dominio (tools):
|
||||
for domain in topology.domains:
|
||||
Agent(
|
||||
description=f"Write tool wrappers for {domain.name}",
|
||||
subagent_type="wxo-tool-author",
|
||||
prompt=f"""
|
||||
Escribí los tool wrappers para el dominio {domain.name}.
|
||||
|
||||
type: {domain.tool_type}
|
||||
tools: {domain.tools}
|
||||
external_system: {domain.external_system}
|
||||
|
||||
Aplicá:
|
||||
- @observable_tool (regla T1)
|
||||
- Coerción Pydantic (issue I-003)
|
||||
- BASE_URL del env (regla T4)
|
||||
- Compat shim inline si es Python (issue I-010)
|
||||
"""
|
||||
)
|
||||
|
||||
# Por cada runbook:
|
||||
for rb in topology.runbooks:
|
||||
Agent(
|
||||
description=f"Write runbook {rb.id}",
|
||||
subagent_type="runbook-author",
|
||||
prompt=f"""
|
||||
Escribí el runbook {rb.id} — {rb.title}.
|
||||
|
||||
domain: {rb.domain}
|
||||
trigger_description: {rb.trigger}
|
||||
preconditions: {rb.preconditions}
|
||||
steps: {rb.steps}
|
||||
success_criteria: {rb.success}
|
||||
escalation_table: {rb.escalation or "none"}
|
||||
|
||||
Guardalo en wxo/knowledge_base/runbooks/runbook-{rb.id}-{rb.slug}.txt
|
||||
"""
|
||||
)
|
||||
|
||||
# Por cada sistema externo a mockear:
|
||||
for sys in topology.mocks:
|
||||
Agent(
|
||||
description=f"Build mock for {sys.name}",
|
||||
subagent_type="mock-builder",
|
||||
prompt=f"""
|
||||
Construí el mock FastAPI para {sys.name}.
|
||||
endpoints: {sys.endpoints}
|
||||
seed_data: {sys.seed_data}
|
||||
behaviors: {sys.behaviors}
|
||||
"""
|
||||
)
|
||||
|
||||
# Por cada scenario de eval:
|
||||
for scn in topology.evals:
|
||||
Agent(
|
||||
description=f"Write eval scenario {scn.name}",
|
||||
subagent_type="eval-author",
|
||||
prompt=f"""
|
||||
Escribí el eval scenario para {scn.agent}.
|
||||
|
||||
scenario_type: {scn.type}
|
||||
runbook_id: {scn.runbook_id}
|
||||
business_input: "{scn.input}"
|
||||
expected_tool_calls_in_order: {scn.tool_calls}
|
||||
expected_response_tokens: {scn.response_tokens}
|
||||
expected_final_state: {scn.final_state}
|
||||
forbidden_tool_calls: {scn.forbidden or []}
|
||||
"""
|
||||
)
|
||||
|
||||
# Web layer:
|
||||
Agent(
|
||||
description="Build web layer",
|
||||
subagent_type="web-layer-builder",
|
||||
prompt=f"""
|
||||
Construí la capa web para {client}.
|
||||
mode: {topology.web_stack} # A o B
|
||||
landing: {topology.landing}
|
||||
trace_view: {topology.trace_view}
|
||||
"""
|
||||
)
|
||||
|
||||
# Si hay backend propio:
|
||||
if topology.has_backend:
|
||||
Agent(
|
||||
description="Build FastAPI backend with OpenAPI tools",
|
||||
subagent_type="backend-tool-builder",
|
||||
prompt=f"""
|
||||
Construí el backend FastAPI para {client}.
|
||||
endpoints: {topology.backend.endpoints}
|
||||
db_schema: {topology.backend.schema}
|
||||
audit_events: {topology.backend.audit_events}
|
||||
"""
|
||||
)
|
||||
```
|
||||
|
||||
## Mientras corren
|
||||
|
||||
Mostrar al usuario:
|
||||
```
|
||||
🚀 Lanzados 12 subagentes en paralelo:
|
||||
✓ wxo-agent-author (orchestrator)
|
||||
✓ wxo-agent-author (specialist_ad)
|
||||
✓ wxo-agent-author (specialist_ops)
|
||||
✓ wxo-tool-author (ad)
|
||||
✓ wxo-tool-author (ops)
|
||||
✓ runbook-author (RB-01)
|
||||
✓ runbook-author (RB-02)
|
||||
✓ mock-builder (ad_mock)
|
||||
✓ mock-builder (ops_mock)
|
||||
✓ eval-author (scenario_reset)
|
||||
✓ eval-author (scenario_restart)
|
||||
✓ web-layer-builder
|
||||
|
||||
Esperando resultados...
|
||||
```
|
||||
|
||||
## Cuando todos terminan
|
||||
|
||||
1. Listar archivos generados (`find <cliente>/ -newer .git -type f`)
|
||||
2. Correr lint:
|
||||
```bash
|
||||
python3 evals/lint_wxo_yaml.py
|
||||
```
|
||||
3. Si hay errores, decidir si re-ejecutar el subagente que falló o pedir
|
||||
ajustes manuales
|
||||
4. Mostrar al usuario un `tree -L 3` de lo que quedó
|
||||
5. Pasar a Fase 6 (recomendaciones)
|
||||
Reference in New Issue
Block a user