---
name: swl:exportar-vault
description: Exporta un resumen compacto de la sesión actual del proyecto al vault SWL personal de Saul (F:\Google Drive\Developer\Obsidian\Vault\SWL\00-Inbox\). Úsalo después de /swl:compactar o al cerrar una sesión productiva cuando quieras que el contenido llegue al segundo cerebro sin esperar a una sincronización manual.
allowed_tools: ["Read", "Write", "Bash", "Glob"]
---

# /swl:exportar-vault — Puente SWL-SES → Vault personal

Eres el puente entre el proyecto activo (sigaf, sigm, swl-ses, ecosistema-multi-agente-ia u otro) y el **vault personal de Saul** ubicado en `F:\Google Drive\Developer\Obsidian\Vault\SWL`. Tu trabajo: producir una nota de Inbox del vault con el resumen de la sesión actual, lista para que Saul la procese cuando abra el vault.

Este comando es **complementario a `/swl:compactar`**, no lo reemplaza. Compactar actualiza `.planning/COMPACTACION.md` del proyecto; exportar-vault propaga lo relevante al vault.

## Señales de que debes usarlo

- Acabas de cerrar `/swl:compactar` con decisiones o aprendizajes importantes.
- Vas a terminar la sesión del día y quieres que los puntos clave queden en el segundo cerebro.
- Saul lo pide explícitamente.
- La sesión produjo una decisión arquitectural que afecta a otros proyectos del ecosistema.

## Paso 0 — Validación del destino y canal de escritura

Hay **dos canales** posibles para escribir al vault. El canal preferido es el
MCP de Obsidian; el filesystem directo es fallback documentado.

### 0a — Validar el vault en filesystem (para lectura y detección)

```bash
test -d "F:\Google Drive\Developer\Obsidian\Vault\SWL\00-Inbox" \
  && echo "[OK] Vault accesible" \
  || echo "[ERROR] Vault no accesible — abortar"
```

Si la ruta no es accesible (por ejemplo, Google Drive no sincronizado o letra de unidad distinta), **abortar con mensaje claro**. No intentes rutas alternativas sin permiso explícito.

### 0b — Detectar disponibilidad del MCP de Obsidian

Verifica si los tools `mcp__obsidian__obsidian_append_content` o
`mcp__obsidian__obsidian_patch_content` están cargados o deferidos:

- Si aparecen como **deferred** en `<system-reminder>`, cargar el schema con
  `ToolSearch(query="select:mcp__obsidian__obsidian_append_content", ...)`.
- Si tras `ToolSearch` siguen sin estar disponibles, el MCP server no está
  corriendo (Obsidian cerrado o plugin Local REST API desactivado). En ese
  caso usar canal de fallback (filesystem directo) — ver Paso 4.

**Por qué MCP-first**: el hook `proteccion-rutas.js` bloquea la herramienta
`Write` con destino fuera del CWD del proyecto. La ruta del vault
(`F:\Google Drive\...`) siempre cae fuera del CWD si trabajas en
`D:\Python\<proyecto>\`. El MCP de Obsidian opera vía HTTPS al puerto 27124
del plugin Local REST API — **no pasa por el hook de filesystem**, así que
nunca dispara el bloqueo.

Defaultear a filesystem cuando el MCP está disponible es un anti-patrón
documentado en `reglas/consultar-vault-primero.md § Workflow forzoso para
escritura al vault`. El bloqueo por `proteccion-rutas.js` no es una falla a
esquivar — es una señal de que el canal correcto es el MCP.

### 0c — Verificar que el vault activo de Obsidian apunta a `Vault\SWL\` (CRÍTICO)

> Origen del paso: sesión 2026-05-13 v1.4.0. El MCP de Obsidian resuelve paths
> relativos contra el **vault que Obsidian tiene abierto**, no contra una
> ruta hardcodeada en el plugin. Si Obsidian abrió un vault distinto del
> esperado (ej. `F:\Google Drive\Developer\Obsidian\Vault\` raíz en lugar
> de `Vault\SWL\`), todas las escrituras del MCP irán al vault equivocado.
> El plugin **crea carpetas inexistentes** sobre la marcha, así que ni
> siquiera obtendrás error — los archivos terminan en una ubicación huérfana.

Verifica antes de cualquier llamada MCP:

```bash
# Path canónico de la config global de Obsidian en Windows
APP="$APPDATA/obsidian/obsidian.json"
node -e "
const fs = require('fs');
const data = JSON.parse(fs.readFileSync(process.argv[1], 'utf8'));
const abierto = Object.values(data.vaults).find(v => v.open === true);
console.log('Vault abierto:', abierto ? abierto.path : 'NINGUNO');
console.log('Esperado:      F:\\\\Google Drive\\\\Developer\\\\Obsidian\\\\Vault\\\\SWL');
console.log('OK:', abierto && abierto.path.endsWith('SWL') ? 'sí' : 'NO');
" "$APP"
```

Resultado esperado:

```
Vault abierto: F:\Google Drive\Developer\Obsidian\Vault\SWL
Esperado:      F:\Google Drive\Developer\Obsidian\Vault\SWL
OK: sí
```

Si `OK: NO` o `Vault abierto: NINGUNO`, **NO usar MCP** — caer al filesystem
para esta sesión y reportar al usuario que debe abrir el vault `SWL` en
Obsidian (File → Open vault → seleccionar `F:\Google Drive\Developer\Obsidian\Vault\SWL`).

### 0d — Verificar que la apiKey del MCP coincide con la del plugin activo

> Origen: cuando el vault activo cambia, la apiKey del plugin Local REST API
> cambia (cada vault tiene su propio `.obsidian/plugins/obsidian-local-rest-api/data.json`
> con apiKey, cert y privateKey distintos). El MCP server registrado en
> Claude.ai tiene una apiKey hardcodeada — si no se actualiza tras cambiar de
> vault, todas las llamadas retornan `40101 Authorization required`.

Si tras `ToolSearch` el MCP carga sus tools pero la primera llamada (ej.
`obsidian_list_files_in_dir`) retorna `Error 40101: Authorization required`,
el síntoma es claro: apiKey desincronizada.

Acción:

1. Leer la apiKey actual del plugin con
   `grep '"apiKey"' "F:/Google Drive/Developer/Obsidian/Vault/SWL/.obsidian/plugins/obsidian-local-rest-api/data.json"`
2. Reportar al usuario que actualice en **claude.ai → Settings → Connectors
   → Obsidian → API Key**. Disconnect + Reconnect tras pegar el valor.
3. Mientras tanto, usar filesystem como fallback para escribir al Inbox.

Si hay procesos zombie de Obsidian o `mcp-obsidian` cliente con apiKey
cacheada, requieren terminación + reinicio de Claude Code para tomar la
nueva apiKey.

## Paso 1 — Identificación del proyecto actual

Detecta qué proyecto eres leyendo:

1. `CLAUDE.md` raíz — primer encabezado H1.
2. `package.json` campo `name` si existe.
3. Si ninguno aclara, usar el nombre de la carpeta raíz del proyecto.

Normaliza el slug del proyecto a kebab-case sin acentos. Ejemplos válidos:

- `sigaf`
- `sigm`
- `swl-software-engineering-system`
- `ecosistema-multi-agente-ia`

## Paso 1.5 — Resolución del nombre canónico desde el vault (CRÍTICO)

Antes de redactar el frontmatter, **debes resolver el nombre canónico exacto** del proyecto leyendo `02-Projects/` del vault. Sin esto, el campo `related_vault_project` queda con un nombre fabricado que no enlaza con ningún nodo del grafo de Obsidian.

Listar proyectos del vault:

```bash
ls "F:/Google Drive/Developer/Obsidian/Vault/SWL/02-Projects/" 2>/dev/null
```

Resultado típico:

```
DEV - Ecosistema Multi-Agente IA OIC-INE.md
DEV - SIGAF.md
DEV - SIGM.md
META - SWL Software Engineering System.md
```

Algoritmo de match (en cascada — cada pasada solo se ejecuta si la anterior no resolvió match único):

**Normaliza ambos lados** a comparación robusta antes de cualquier pasada:

- Strip extensión `.md`.
- Strip prefijo `DEV - ` o `META - ` (cualquier prefijo seguido de ` - `).
- Lowercase.
- Sin acentos.
- Reemplaza espacios y guiones por nada (compactar).

Aplica el mismo procesamiento al slug del proyecto local.

**Pasada 1 — Match exacto**:

- Si la cadena normalizada del slug local coincide carácter a carácter con la de algún canónico, ese es el match. Caso típico: `sigaf` ↔ `DEV - SIGAF`.

**Pasada 2 — Match por prefijo bidireccional**:

- Si la cadena del slug local es **prefijo** de la cadena de algún canónico, ese canónico matchea. Ej: `ecosistemamultiagenteia` es prefijo de `ecosistemamultiagenteiaoicine` → match con `DEV - Ecosistema Multi-Agente IA OIC-INE`.
- Inversamente: si la cadena de algún canónico es prefijo de la del slug local, también matchea (cubre el caso opuesto: vault con nombre más corto que el slug del proyecto).
- Solo se acepta el match si la pasada produce **exactamente 1** candidato. Si hay 2+ ambiguos, NO usar — pasar a siguiente pasada con el alias o fallback final, listando los candidatos en el WARNING del Paso 5.

**Pasada 3 — Aliases conocidos**:

- Si ninguna pasada anterior resolvió, intenta con sinónimos del slug local antes del fallback (ver lista de aliases más abajo). Para cada alias, repite Pasada 1 y Pasada 2.

**Pasada 4 — Fallback**:

- Si todo lo anterior es vacío:
  - Usar como `related_vault_project` el valor `[[DEV - {Nombre-Title-Case}]]` (fallback antiguo).
  - **Reportar warning explícito al usuario** en el paso 5 indicando que no se encontró nodo canónico y sugerir crear `02-Projects/DEV - {Nombre}.md` en el vault.

Resultado del algoritmo: el nombre canónico es el basename del archivo sin `.md` (con su prefijo `DEV - ` o `META - ` original intacto).

Ejemplos de match esperado (con la pasada que lo resuelve):

| Slug local                        | Normalizado local              | Canónico que matchea            | Pasada                                                                   | Nombre canónico resuelto                   |
| --------------------------------- | ------------------------------ | ------------------------------- | ------------------------------------------------------------------------ | ------------------------------------------ |
| `sigaf`                           | `sigaf`                        | `sigaf`                         | 1 (exacto)                                                               | `DEV - SIGAF`                              |
| `sigm`                            | `sigm`                         | `sigm`                          | 1 (exacto)                                                               | `DEV - SIGM`                               |
| `swl-software-engineering-system` | `swlsoftwareengineeringsystem` | `swlsoftwareengineeringsystem`  | 1 (exacto)                                                               | `META - SWL Software Engineering System`   |
| `ecosistema-multi-agente-ia`      | `ecosistemamultiagenteia`      | `ecosistemamultiagenteiaoicine` | 2 (prefijo del slug en canónico)                                         | `DEV - Ecosistema Multi-Agente IA OIC-INE` |
| `swl-ses`                         | `swlses`                       | ninguno (ver nota)              | 3 (alias → reemplaza slug por `swlsoftwareengineeringsystem` y repite 1) | `META - SWL Software Engineering System`   |

**Nota sobre el caso `swl-ses`** — un lector cuidadoso puede preguntarse por qué Pasada 2 (prefijo) no captura este caso, dado que `swlses` y `swlsoftwareengineeringsystem` comparten el inicio `swls`. La verificación carácter a carácter:

```
pos:    0 1 2 3 4 5
swlses: s w l s e s
swlsof: s w l s o f t w a r e ...
                ^
                divergen aquí (e vs o)
```

`swlses` **no es prefijo** de `swlsoftwareengineeringsystem` — comparten 4 caracteres pero divergen en la posición 4. Por eso Pasada 2 falla y se necesita la sustitución de alias en Pasada 3. Esta nota existe para prevenir el malentendido común de que "comparten algunas letras iniciales" implica "uno es prefijo del otro".

**Aliases conocidos** — si el slug local no matchea directo, intenta estos sinónimos antes del fallback:

- `swl-ses` → buscar `swl-software-engineering-system` o `swlsoftwareengineeringsystem`.
- Cualquier slug que empiece con `swl-` y termine en `-ses` o `-software-engineering-system` → trata como `swl-software-engineering-system`.

Guarda el resultado en dos variables internas para usar más abajo:

- `nombre_canonico_completo` — ej. `META - SWL Software Engineering System`. Va dentro de `[[ ]]` en el frontmatter.
- `proyecto_slug` — el slug original sin alterar. Va en el filename y en tags.

## Paso 2 — Recolección del contenido de la sesión

Junta estas fuentes (las que existan):

1. **Última compactación:** `.planning/COMPACTACION.md` o `.planning/COMPACT.md`.
2. **Estado actual:** `.planning/ESTADO.md` o `.planning/STATE.md`.
3. **Últimos aprendizajes del APRENDIZAJES.md** — solo las entradas con fecha del día en curso o las últimas 10.
4. **Git log del día:** `git log --oneline --since="00:00" --until="23:59"`.
5. **Git status actual:** `git status --short`.

## Paso 3 — Síntesis

Produce un resumen de **no más de 500 palabras** con esta estructura:

```markdown
---
type: export-swl
status: pending-review
tags: [export, inbox, swl-{proyecto-slug}]
created: {fecha-hoy YYYY-MM-DD}
source: swl-ses
project: "{nombre-proyecto}"
project_path: "{ruta-absoluta}"
related_vault_project: "[[{nombre_canonico_completo}]]"
reviewed: false
---

# Export SWL-SES → Vault ({fecha-hoy}) — {nombre-proyecto}

## Sesión

- **Fecha:** YYYY-MM-DD
- **Horario:** HH:MM a HH:MM
- **Rama git:** {rama}
- **Último commit:** {sha7} — {mensaje}

## Logros de la sesión

- Punto 1
- Punto 2
- Punto 3

## Decisiones tomadas

- **{título decisión}** — razón en 1 línea.
- ...

## Aprendizajes nuevos (candidatos a 04-Resources del vault)

- **{aprendizaje}** — fuente: `{archivo}` o sesión.

## Métricas que cambiaron

| Métrica   | Antes | Después |
| --------- | ----- | ------- |
| LOC       |       |         |
| Endpoints |       |         |
| Tests     |       |         |

## Bloqueantes o deuda detectada

-

## Acción sugerida al leer en el vault

Ejecutar `/sync-projects {proyecto-slug}` en el vault para integrar los cambios formalmente.

---

**Archivos fuente consultados:**

- `.planning/COMPACTACION.md` (última)
- `.planning/APRENDIZAJES.md` (últimas entradas)
- Git log del día

**Notas:**

- Este archivo vive en 00-Inbox/ del vault. Saul lo procesa manualmente o con `/sync-projects`.
- No sobreescribe nada en `02-Projects/`, `04-Resources/` ni `07-Decisions/` del vault.
```

## Paso 4 — Escritura en el vault

El archivo destino es:

```
F:\Google Drive\Developer\Obsidian\Vault\SWL\00-Inbox\YYYY-MM-DD_HHMM_export-{proyecto-slug}.md
```

Con UTF-8 sin BOM. Usar **uno de dos canales** según disponibilidad:

### Canal A (preferido) — MCP de Obsidian

Si el Paso 0b confirmó que `mcp__obsidian__obsidian_append_content` está
disponible (cargado directamente o tras `ToolSearch`), usar este canal:

```jsonc
// La ruta es RELATIVA al vault root (no incluye F:\...\SWL\)
mcp__obsidian__obsidian_append_content({
  filepath: "00-Inbox/YYYY-MM-DD_HHMM_export-{proyecto-slug}.md",
  content: "<contenido completo del export>"
})
```

Ventajas frente al filesystem:

- **No pasa por `proteccion-rutas.js`** — el MCP opera vía HTTPS al puerto
  27124, fuera del flujo de Bash/Write/Edit.
- **Sin staging intermedio**: escribe directamente al archivo final del vault.
- **Auditable**: el plugin Local REST API de Obsidian registra el acceso.
- **Cross-OS**: el wrapper funciona idéntico en Windows/macOS/Linux sin
  manejar separators de path.

Notas operativas:

- Si el archivo ya existe con ese timestamp (raro), agregar sufijo `_b`
  al nombre antes de invocar `append_content`. El MCP de obsidian no
  sobreescribe si el archivo existe — `append` agrega al final.
- Si se necesita escribir secciones específicas en lugar de un archivo
  completo, usar `mcp__obsidian__obsidian_patch_content` con
  `target_type: "heading"`.

### Canal B (fallback) — Filesystem directo

Solo cuando el MCP no responde tras `ToolSearch` (Obsidian cerrado, plugin
desactivado, sin red local). **Esto va a chocar con `proteccion-rutas.js`**
si el CWD es el directorio del proyecto, así que requiere ejecución vía
Bash con redirección o vía un comando del CLI nativo del SO:

```powershell
# PowerShell — UTF-8 sin BOM
$encoding = New-Object System.Text.UTF8Encoding($false)
[System.IO.File]::WriteAllText($path, $content, $encoding)
```

```bash
# Bash + heredoc — UTF-8 sin BOM por default en Node 18+
cat > "$path" <<'EOF'
<contenido del export>
EOF
```

**No usar `Write` directo** desde la herramienta del agente — `proteccion-rutas.js`
lo bloquea. Si por algún motivo el agente necesita usar `Write`, primero
escribe a `_userland/staging/<timestamp>.md` dentro del CWD, luego mueve con
`Bash` (`mv` o PowerShell `Move-Item`).

Reportar al usuario qué canal se usó:

- Canal A → `[OK] Vía: MCP Obsidian (puerto 27124)`
- Canal B → `[OK] Vía: filesystem directo (MCP no disponible)`
- Canal Híbrido → `[OK] Vía: filesystem para Inbox, MCP para promociones`

### Modo HÍBRIDO (validado en sesión 2026-05-13)

Cuando la sesión incluye **autorización ampliada para promover documentos**
a `02-Projects/`, `07-Decisions/` y `04-Resources/`, el flujo óptimo combina
ambos canales:

1. **Inbox** (`00-Inbox/YYYY-MM-DD_HHMM_export-{slug}.md`): usar siempre
   **filesystem directo via Bash heredoc con ruta absoluta** (canal B). Razón:
   el Bash heredoc bypassa cualquier desalineación del vault activo de
   Obsidian — escribe directamente al disco en la ruta exacta.

2. **Promociones** (a `02-Projects/`, `07-Decisions/`, `04-Resources/`):
   usar **MCP append_content** (canal A) tras validar Pasos 0c y 0d. Razón:
   las promociones requieren enlaces bidireccionales con `[[...]]` que el
   plugin de Obsidian indexa al detectar la escritura. El filesystem directo
   crea el archivo pero no dispara la reindexación hasta que Obsidian
   detecte el cambio.

3. **Aprobación de revisiones** (cambiar `status: pending-review` → `reviewed`
   en frontmatter): si el archivo está en `00-Inbox/`, usar `sed` via Bash;
   si está en `02-Projects/` etc., usar `mcp__obsidian__obsidian_patch_content`
   con `target_type: "frontmatter"`. Validado que `patch_content` puede
   responder 404 en algunos archivos pre-existentes — caer al filesystem si
   falla.

Reportar al usuario el desglose final del modo híbrido:

```
[OK] Inbox creado via filesystem: F:\...\00-Inbox\...md
[OK] 3 promociones via MCP: 02-Projects, 07-Decisions, 04-Resources
[OK] Revisión aprobada (reviewed: true) en el Inbox
```

## Paso 4b — Verificación post-escritura (obligatorio)

**Inmediatamente después** de cada escritura del Paso 4 (Inbox, promociones en
`02-Projects/`, `07-Decisions/`, `04-Resources/`, `10-Archive/`), confirma que el
archivo en disco **existe y tiene contenido sustantivo**. Sin este paso, Obsidian
puede mostrar nodos fantasma (pestaña con título pero cuerpo vacío) cuando el MCP
falló con `40101`, timeout o `append_content` sobre ruta incorrecta.

### Cuándo verificar

| Escritura                                                     | Verificar                                                     |
| ------------------------------------------------------------- | ------------------------------------------------------------- |
| Export en `00-Inbox/`                                         | **Siempre**                                                   |
| Append a `02-Projects/DEV - *.md`                             | **Siempre** (leer tramo final o archivo completo si es corto) |
| Nota nueva en `07-Decisions/`, `04-Resources/`, `10-Archive/` | **Siempre**                                                   |
| Solo `reviewed: true` en Inbox existente                      | Opcional (el archivo ya existía)                              |

### Cómo verificar (orden de preferencia)

1. **MCP** — `obsidian_get_file_contents` con path **relativo al vault SWL**
   (sin prefijo `F:\...`):
   ```json
   { "filepath": "00-Inbox/2026-05-18_1530_export-swl-ses.md" }
   ```
2. **Filesystem** — si el Paso 4 usó canal B, leer el mismo path absoluto con
   `Read` o `Get-Content` y comparar longitud.

### Criterios de aprobación (todos deben cumplirse)

| #   | Criterio            | Umbral                                                                                                                                                   |
| --- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1   | El archivo existe   | Sin error 404 / `ENOENT`                                                                                                                                 |
| 2   | Longitud del cuerpo | ≥ **500 caracteres** (sin contar solo frontmatter vacío)                                                                                                 |
| 3   | Marcador de export  | Contiene `type: export-swl` en frontmatter **o** al menos una sección `## Logros de la sesión` / `## Sesión` / `## Decisiones` con texto bajo el heading |
| 4   | No es fantasma      | El cuerpo **no** es solo el título del archivo, una línea en blanco, o el nombre del nodo sin párrafos                                                   |

Si el export es deliberadamente corto (<500 caracteres), bajar el umbral a
≥ **200 caracteres** solo si el frontmatter incluye `type: export-swl` y al
menos un bullet bajo `## Logros` o `## Sesión`; en caso contrario, tratar como
fallo.

### Si la verificación falla

1. **No** reportar `[OK] Export creado` al usuario.
2. Registrar en la salida: `[FAIL] Verificación post-escritura: <motivo>`.
3. **Un reintento** con el canal alternativo (MCP ↔ filesystem del Paso 4).
4. Si sigue fallando: reconstruir el Markdown desde `.planning/COMPACTACION.md`
   - artefactos de sesión y escribir de nuevo; si aún falla, abortar y pedir
     al usuario revisar Obsidian (vault activo Paso 0c, apiKey Paso 0d).
5. Si Obsidian ya abrió una pestaña fantasma: cerrar la pestaña en el IDE de
   Obsidian; **no** dejar el tab apuntando a un path que no pasó verificación.

### Salida interna (para el Paso 5)

Guardar mentalmente (o en el reporte):

```
[OK] Verificación: 00-Inbox/2026-05-18_1530_export-swl-ses.md — 2847 chars, secciones OK
```

o

```
[FAIL] Verificación: cuerpo 42 chars — reintento vía filesystem
```

## Paso 5 — Confirmación

Reporta al usuario **solo si el Paso 4b aprobó** el Inbox (y cada promoción, si aplica):

- Ruta exacta del archivo creado.
- Resultado del Paso 4b (caracteres verificados o `[FAIL]` si abortaste).
- Conteo de palabras.
- **Nombre canónico resuelto**: indicar qué nodo de `02-Projects/` enlazó el export. Si no hubo match, marcar el warning explícito.
- Recordatorio: "Al abrir el vault en tu próxima sesión, ejecuta `/sync-projects {proyecto-slug}` para integrar formalmente estos cambios."

Formato esperado cuando hay match:

```
[OK] Export creado: F:\...\2026-05-04_1748_export-swl-ses.md (487 palabras)
[OK] Verificación post-escritura: 3124 chars, type: export-swl, secciones OK
[OK] Enlace canónico: [[META - SWL Software Engineering System]]

Próximo paso: al abrir el vault, ejecuta:
  /sync-projects swl-ses
```

Formato esperado cuando NO hay match:

```
[OK] Export creado: F:\...\2026-05-04_1748_export-mi-proyecto.md (487 palabras)
[WARNING] No se encontró nodo canónico en 02-Projects/. Usado fallback: [[DEV - Mi Proyecto]]
  Sugerencia: crear F:\...\02-Projects\DEV - Mi Proyecto.md en el vault para que el grafo conecte el export con el proyecto.

Próximo paso: al abrir el vault, ejecuta:
  /sync-projects mi-proyecto
```

## Restricciones

- **No sobrescribir** archivos existentes con el mismo nombre. Si por azar existe uno con el mismo timestamp (raro), agrega sufijo `_b`.
- **No escribir** en otras carpetas del vault. Solo `00-Inbox/`.
- **No tocar** `.planning/` del proyecto.
- **Abortar silenciosamente** si el vault no existe, reportando al usuario. No asumir rutas alternativas.

## Anti-patrones

- Exportar 5000 palabras cuando la sesión fue pequeña. El resumen debe ser denso.
- Duplicar con el `COMPACTACION.md` del proyecto (copiar pega tal cual). El export es una **síntesis para vault**, no un espejo.
- Intentar escribir directamente en `02-Projects/` del vault. Eso es zona ⚠️ en el vault — solo Saul decide si promoverlo.
- Usar rutas con backslash no escapadas en código generado.
- **Defaultear a filesystem cuando el MCP de Obsidian está disponible**.
  El bloqueo por `proteccion-rutas.js` no es una falla a esquivar con Bash
  staging — es señal de que el canal correcto es el MCP. Ver Paso 0b.
- **Recurrir al workaround del filesystem antes de cargar el schema del
  MCP con `ToolSearch`**. Tools deferred ≠ tools ausentes — el MCP server
  está corriendo, solo falta cargar el schema. Cargar antes de defaultear.
- **Declarar éxito sin Paso 4b**. Un `append_content` o `Write` que no lanza
  error no garantiza contenido en disco ni en el índice de Obsidian — genera
  nodos fantasma en el grafo. Siempre leer de vuelta antes del `[OK]`.

## Relación con otros comandos SWL

- `/swl:compactar` → actualiza `.planning/` del proyecto. Luego `/swl:exportar-vault` propaga al vault. Secuencia natural.
- `/swl:aprender` → captura aprendizajes en el proyecto. Luego `/swl:exportar-vault` los envía al vault como candidatos.
- `/swl:checkpoint` → guarda estado del proyecto. No requiere export al vault (es recuperación interna).

## Ejemplo de invocación

```
/swl:compactar
/swl:exportar-vault
```

Produce:

```
[OK] Export creado: F:\Google Drive\Developer\Obsidian\Vault\SWL\00-Inbox\2026-04-16_2130_export-sigaf.md (487 palabras)
[OK] Verificación post-escritura: 2980 chars, secciones OK
[OK] Vía: MCP Obsidian (puerto 27124)
[OK] Enlace canónico: [[DEV - SIGAF]]

Próximo paso: al abrir el vault, ejecuta:
  /sync-projects sigaf
```

## Historial de cambios del comando

- **v1.4.1** (2026-05-18) — **Paso 4b — Verificación post-escritura**
  obligatoria tras cada escritura MCP o filesystem. Origen: exports MCP fallidos
  (40101 / vault activo incorrecto) dejaron pestañas y nodos en el grafo sin
  archivo en disco o con cuerpo vacío; reconstrucción manual desde
  `COMPACTACION.md`. Criterios: existencia, ≥500 chars (o ≥200 con frontmatter
  completo), secciones de export, anti-fantasma; un reintento con canal alternativo;
  no reportar `[OK]` sin verificación. Anti-patrón y ejemplos del Paso 5
  actualizados.

- **v1.4.0** (2026-05-13) — Agregados Pasos 0c y 0d con verificación previa
  del vault activo de Obsidian y de la apiKey del MCP. Origen: sesión
  2026-05-13 con autorización ampliada del usuario para promover docs;
  el MCP escribió `02-Projects/DEV - swl-ses.md` en `Vault\` raíz en lugar
  de `Vault\SWL\` porque Obsidian tenía abierto el vault un nivel arriba
  del esperado. Hallazgo crítico: el plugin Local REST API resuelve paths
  relativos contra el vault que Obsidian tiene abierto en `obsidian.json`
  global, no contra una ruta hardcodeada. Si el vault activo está mal,
  el MCP escribe a la ubicación equivocada sin error (el plugin crea
  carpetas inexistentes). Agregado también Paso 0d para apiKey
  desincronizada (síntoma `40101 Authorization required`). Y nuevo
  modo HÍBRIDO en Paso 4: filesystem directo para Inbox + MCP para
  promociones, validado en la misma sesión.

- **v1.3.8** (2026-05-11) — Agregado flujo MCP-first en Paso 4 con detección
  en Paso 0b. Origen: en la sesión v1.3.4 → v1.3.8 el comando defaultó a
  `Write` directo al filesystem que fue bloqueado por `proteccion-rutas.js`.
  El fallback al MCP funcionó pero quedó manual. Esta versión documenta
  el orden de preferencia (MCP primero, filesystem como fallback explícito)
  y agrega la nota de "tools deferred ≠ tools ausentes" en anti-patrones.
  Aplicación de la regla `consultar-vault-primero.md § Workflow forzoso
para escritura al vault`.
