7.6 KiB
Skill global: cargar contexto de Docmost al iniciar conversación
Contexto
El usuario quiere que, al iniciar cualquier conversación de Claude Code, se cargue automáticamente el
contexto del proyecto actual desde Docmost (MCP mcp__docmost__*): listar los spaces, identificar cuál
corresponde al proyecto en el que se está trabajando, y leer el contenido completo de todas sus páginas.
Investigación realizada (en modo solo-lectura):
- No existe ningún CLAUDE.md global ni hook
SessionStarthoy en~/.claude/settings.json(solo hay un hookNotificationpara email vía Gmail). - Las skills se activan por coincidencia de descripción, no automáticamente al iniciar sesión. Para que
algo corra siempre al inicio, el único mecanismo real es un hook
SessionStart, cuyostdoutse inyecta como contexto adicional (esto es lo que documentahooks-guide.mdde Claude Code, ej. "Re-inject context after compaction"). El hook (bash) no puede llamar herramientas MCP directamente — eso solo lo puede hacer el modelo. Por eso el diseño es: hook (bash) → inyecta instrucción → skill (markdown) → modelo ejecuta las llamadas MCP reales. - Ya existe en
background-orchestrator/SKILL.mduna lógica de detección de proyecto reutilizable (package.json→pyproject.toml→ basename del repo git), que se reutiliza aquí tal cual. - Verifiqué en vivo el MCP de Docmost:
list_spacesdevuelve{id, name, slug, description, ...};list_pages({spaceId})devuelve el árbol de páginas (id, title, parentPageId) sin contenido;get_page({pageId})sí devuelve el contenido completo (content, markdown). Los nombres de space no siempre calzan literal con el nombre del repo (ej. space "Create React SSR App" vs. un repo en kebab-case), así que el match debe ser normalizado (minúsculas, sin espacios/guiones), no exacto. Algunos spaces ya tienen 30+ páginas con contenido extenso.
Decisiones confirmadas con el usuario:
- Leer todo siempre — al detectar el space, leer el contenido completo de todas sus páginas (sin recortar ni resumir antes de cargar).
- Si no hay match — preguntar al usuario (mostrar los spaces disponibles y dejar que elija uno o indique que no corresponde ninguno).
- Alcance — el hook solo actúa si el cwd está dentro de un repo git; fuera de un repo no intenta nada.
Diseño
1. Script del hook — ~/.claude/hooks/docmost-session-start.sh (nuevo, chmod +x)
Bash puro, sin llamadas MCP (no puede hacerlas). Solo detecta el proyecto y, si aplica, imprime a stdout
una instrucción para que el modelo invoque la skill. Si no está en un repo git, no imprime nada (exit 0
silencioso → no se inyecta contexto ni se gasta turno en esto).
#!/bin/bash
# Solo actuar dentro de un repo git (decisión confirmada con el usuario)
git rev-parse --show-toplevel >/dev/null 2>&1 || exit 0
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)")
cat <<EOF
[docmost-context] Nueva conversación detectada en el proyecto git "$PROJECT_NAME" ($(pwd)).
Antes de responder al primer mensaje del usuario, invoca la skill "docmost-context" (Skill tool,
skill: docmost-context, args: "$PROJECT_NAME") para cargar el contexto del proyecto desde Docmost.
Hazlo una sola vez al inicio de esta conversación; no la vuelvas a invocar en turnos posteriores salvo
que el usuario lo pida explícitamente.
EOF
2. Registrar el hook en ~/.claude/settings.json (editar)
Añadir la clave SessionStart dentro de hooks (se conserva el Notification existente). Se registran
tres matchers por separado (startup, resume, clear) — deliberadamente sin compact, para no
releer 30+ páginas completas cada vez que el contexto se compacta a mitad de conversación:
"SessionStart": [
{ "matcher": "startup", "hooks": [{ "type": "command", "command": "/home/aleleba/.claude/hooks/docmost-session-start.sh" }] },
{ "matcher": "resume", "hooks": [{ "type": "command", "command": "/home/aleleba/.claude/hooks/docmost-session-start.sh" }] },
{ "matcher": "clear", "hooks": [{ "type": "command", "command": "/home/aleleba/.claude/hooks/docmost-session-start.sh" }] }
]
También añadir a permissions.allow: "mcp__docmost__list_spaces" (los demás —list_pages, get_page,
search— ya están permitidos desde background-orchestrator).
3. Skill global — ~/.claude/skills/docmost-context/SKILL.md (nuevo)
---
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 el contenido completo
de todas sus páginas. 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]"
---
Cuerpo (workflow):
- Determinar el nombre del proyecto: usar el argumento recibido si viene; si no, repetir la misma
detección de
background-orchestrator(package.json→pyproject.toml→ basename del repo git). - Listar spaces:
mcp__docmost__list_spaces. - Buscar coincidencia comparando el nombre del proyecto contra
nameyslugde cada space, normalizando (minúsculas, sin espacios/guiones/guiones bajos) — match exacto normalizado, no substring débil.- Una sola coincidencia → usarla directamente, sin confirmar con el usuario.
- Cero coincidencias → usar
AskUserQuestionmostrando la lista de spaces disponibles, dejando elegir uno existente o responder que ninguno corresponde (en ese caso, no cargar nada y continuar la conversación normalmente). - Varias coincidencias ambiguas → preguntar igual, mostrando solo los candidatos ambiguos.
- Leer el space completo:
mcp__docmost__list_pages({spaceId})para obtener todas las páginas, y luegomcp__docmost__get_page({pageId})para cada una (contenido completo, sin omitir ninguna). - No repetir el dump al usuario: una vez cargado el contenido al contexto, responder con un mensaje breve (1-2 líneas) indicando qué space y cuántas páginas se cargaron — no transcribir el contenido de las páginas en el chat.
- Ejecutar esto una sola vez por conversación (al primer turno, disparado por el hook); no repetir en turnos siguientes salvo pedido explícito del usuario.
Verificación
chmod +x ~/.claude/hooks/docmost-session-start.shy ejecutarlo manualmente dentro de un repo git y fuera de uno, confirmando que imprime la instrucción solo en el primer caso.- Iniciar una conversación nueva (
startup) dentro de un repo con space conocido (ej.Ro-ut) y confirmar que el modelo invoca la skill sin que el usuario lo pida, y que reporta el space/páginas cargadas en 1-2 líneas. - Probar dentro de un repo sin space coincidente y confirmar que se dispara
AskUserQuestioncon la lista de spaces. - Si en la prueba real el
stdoutplano del hook no llega como contexto, usar como fallback el formato JSON documentado:{"hookSpecificOutput": {"hookEventName": "SessionStart", "additionalContext": "..."}}. - Confirmar que
/cleartambién dispara la carga, y quecompact(compactación automática) no la repite.