Fase 2: 04_sanitize.py - scrubbing de secretos de skills/agentes/plans (10 secretos unicos, gate en verde)

This commit is contained in:
2026-07-29 00:35:59 +00:00
parent 21bc219f31
commit 837f91060f
79 changed files with 10153 additions and 0 deletions
@@ -0,0 +1,164 @@
---
name: docmost-context
description: >-
Carga el contexto del proyecto actual desde Docmost (MCP) al inicio de una conversación: lista los
spaces, identifica cuál corresponde al proyecto del directorio actual, y lee solo las páginas
más relevantes (arquitectura, estructura, tecnologías, estilo de código, etc.). Se activa
automáticamente vía el hook SessionStart (ver ~/.claude/hooks/docmost-session-start.sh) — no
requiere que el usuario la invoque a mano, aunque también responde a "carga el contexto de
Docmost", "lee el proyecto en Docmost", "/docmost-context".
effort: medium
argument-hint: "[nombre del proyecto, si ya se conoce]"
---
# docmost-context — Cargar contexto relevante del proyecto desde Docmost
Lee solo las páginas más importantes de Docmost para arrancar la conversación con contexto
estructural, en lugar de leer todo ciegamente.
Se dispara automáticamente al inicio de la conversación vía el hook `SessionStart`
(`~/.claude/hooks/docmost-session-start.sh`), que inyecta una instrucción con el `PROJECT_NAME` ya
detectado. También puede invocarse a mano.
## Workflow
### 1. Determinar el nombre del proyecto
- Si vino como argumento (`args`), úsalo directamente.
- Si no, detéctalo en este orden de prioridad (igual que `agent-orchestrator`):
```bash
PROJECT_NAME=$(jq -r '.name // empty' package.json 2>/dev/null)
[ -z "$PROJECT_NAME" ] && PROJECT_NAME=$(grep -oP '^\s*name\s*=\s*"\K[^"]+' pyproject.toml 2>/dev/null | head -1)
[ -z "$PROJECT_NAME" ] && PROJECT_NAME=$(basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)")
```
### 2. Listar spaces
Llama a `mcp__docmost__list_spaces`.
### 3. Buscar la coincidencia
Compara `PROJECT_NAME` contra el `name` y el `slug` de cada space, **normalizando** ambos lados antes de
comparar: minúsculas, sin espacios/guiones/guiones bajos, y **sin el scope de npm** si lo tiene (quita el
prefijo `@algo/` de nombres tipo `@aleleba/create-react-component-library` → `create-react-component-library`)
— los nombres de space no siempre calzan literal con el nombre del repo o del `package.json`
(ej. space "Create React SSR App" vs. repo `create-react-ssr-app`, o `@aleleba/create-react-component-library`
vs. space "Create React Component Library").
Si tras esa normalización no hay match exacto, prueba también un match por contención (el nombre
normalizado de uno está contenido en el del otro) antes de darte por vencido.
- **Una sola coincidencia** → úsala directamente, sin confirmar con el usuario.
- **Cero coincidencias** → usa `AskUserQuestion` mostrando la lista de spaces disponibles (nombre +
descripción) y deja elegir uno existente, o la opción de que ninguno corresponde. Si el usuario dice
que ninguno corresponde, no cargues nada y continúa la conversación normalmente — no insistas.
- **Varias coincidencias ambiguas** → pregunta igual, mostrando solo los candidatos ambiguos.
### 4. Dos pasos: puntuar y leer
Llama a `mcp__docmost__list_pages({spaceId})` para obtener el árbol completo de páginas.
No llames a `get_page` todavía. Primero **puntuar** todas las páginas, luego **leer** solo las seleccionadas.
#### Paso A: Puntuar cada página
Asigna un score a cada página con esta fórmula:
```
score = keyword_score + depth_score + name_quality + topic_bonus
```
**keyword_score** (2 puntos por cada keyword que coincida con el nombre o ruta de la página):
| Categoría | Keywords |
|---|---|
| Arquitectura y estructura | arquitectura, estructura, stack, tecnologías, componentes, layout, routing, routes, endpoints, models, schema, database, base de datos |
| Configuración y herramientas | config, configuration, tsconfig, vite.config, next.config, eslint, prettier, biome, tailwind, tailwind.config, dependencies, dependencias |
| Convenios y estilo | estilo de código, convenciones, code style, coding conventions, guidelines, guía, style guide |
| Onboarding y setup | onboarding, setup, getting started, entorno, environment, variables, entorno, configuración, install, instalación |
| Testing | testing, tests, jest, vitest, cypress, playwright, e2e, integration |
| Deploy y CI/CD | deploy, deployment, CI/CD, pipeline, github actions, vercel, netlify, docker, docker-compose |
| Migración y estado | migración, migrations, roadmap, estado actual, changelog, release |
| API y backend | API, endpoint, route, controller, service, middleware |
| Genéricos (páginas raíz) | overview, introduction, getting started, readme, documentación, inicio, home |
**depth_score** (basado en la profundidad en la jerarquía):
- 0 niveles (página raíz): **+3**
- 1 nivel de profundidad: **+2**
- 2 niveles de profundidad: **+1**
- 3+ niveles de profundidad: **+0**
**name_quality** (1 si el nombre es significativo, 0 si no):
- **+1** si el nombre no es "Untitled", "Sin título", vacío, o genérico sin contexto
- **+0** si el nombre es vacío, "Untitled", o similar
**topic_bonus** (2 puntos si la página coincide con el tema del usuario, 0 si no):
Si el mensaje del usuario o el hook mencionan un tema específico, aplica bonus:
| Tema del usuario | Keywords de bonus |
|---|---|
| Testing | test, jest, vitest, cypress, playwright, e2e |
| Deploy/CI/CD | deploy, CI/CD, pipeline, docker, vercel, github actions |
| Database | database, schema, migration, prisma, drizzle, kysely |
| UI/Components | component, design system, tailwind, theme, layout |
| API/Backend | API, endpoint, route, controller, service |
El topic_bonus es un **extra** sobre el keyword_score base. No reemplaza las keywords de
arquitectura/estructura — se suma a ellas.
#### Paso B: Reglas de selección
Clasifica las páginas en tres tiers según el score:
| Tier | Score | Qué hacer |
|---|---|---|
| **Crítico** | >= 8 | Leer completo con `get_page` |
| **Importante** | 4-7 | Leer título + snippet (primeros 300 caracteres) |
| **Nice-to-know** | < 4 | No leer contenido, solo anotar título |
**Límite de páginas completas:** máximo **5 páginas** se leen en detalle.
**Regla de selección según el total de páginas del space:**
| Total páginas | Páginas completas | Snippets | Ignorar |
|---|---|---|---|
| 0-3 | Todas | 0 | 0 |
| 4-10 | Top 3-5 | Resto | 0 |
| 11+ | Top 5 | Siguientes 5 | Resto |
**Lectura parcial con contenido-gated expansion (para tier "Importante"):**
1. Leer título + primeros 300 caracteres del contenido.
2. Evaluar: ¿el snippet contiene información relevante para el tema que el usuario está trabajando?
3. Si SÍ → leer la página completa con `get_page`.
4. Si NO → descartar, no leer más.
**Páginas ignoradas:** solo anotar el título en el reporte final. No llamar a `get_page`.
### 5. Leer solo lo seleccionado
Para cada página seleccionada:
- **Tier Crítico** (hasta 5 páginas): llamar a `mcp__docmost__get_page({pageId})` y leer el contenido completo.
- **Tier Importante** (lectura parcial): llamar a `get_page`, leer solo título + primeros 300 caracteres.
Si el snippet es relevante para el tema del usuario, leer el resto.
- **Tier Nice-to-know**: no llamar a `get_page`. Solo usar el título de la lista.
### 6. Reportar, no transcribir
Una vez cargado, responde con un mensaje breve (1-2 líneas): qué space se usó y cuántas páginas
relevantes se cargaron. No repitas el contenido de las páginas en el chat — ya quedó en tu contexto
para usarlo cuando haga falta.
Ejemplo de reporte:
```
Contexto cargado desde Docmost:
- Space: <nombre>
- Fase 1 (baseline): <n> páginas (arquitectura, estructura, tecnologías)
- Fase 2 (contexto específico): <n> páginas (<temas>)
Total: <n> páginas relevantes cargadas.
```
### 7. Una sola vez por conversación
Ejecuta esto una sola vez, al primer turno disparado por el hook. No lo repitas en turnos posteriores
de la misma conversación salvo que el usuario lo pida explícitamente (ej. "recarga el contexto de
Docmost").