---
name: open_obsidian_vault
kind: function
lang: py
domain: obsidian
version: "1.0.0"
purity: impure
signature: "def open_obsidian_vault(vault: str, register_if_missing: bool = True, launch: bool = True, config_path: str = '') -> dict"
description: "Abre un vault en la app de escritorio Obsidian construyendo el URI obsidian://open?vault=<name> (name = basename del path o el propio nombre, URL-encodeado) y lanzandolo desacoplado via xdg-open. Si recibe una ruta existente no registrada y register_if_missing=True, la registra antes componiendo register_obsidian_vault (open=True). Con launch=False construye el URI sin lanzar nada (util en tests)."
tags: [obsidian, vault, open, launch, uri, desktop-app, obsidian-json]
uses_functions: ["register_obsidian_vault_py_obsidian"]
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: ["os", "subprocess", "urllib.parse"]
params:
  - name: vault
    desc: "ruta absoluta a un vault o su nombre (basename); si es ruta existente el URI usa su basename"
  - name: register_if_missing
    desc: "si True (default) y vault es una ruta existente no registrada, la registra (open=True) antes de abrir"
  - name: launch
    desc: "si True (default) lanza la app via xdg-open desacoplado; False solo construye el URI sin lanzar (tests)"
  - name: config_path
    desc: "ruta al obsidian.json de la app pasada a register_obsidian_vault; vacio usa ~/.config/obsidian/obsidian.json"
output: "dict con vault (arg original), uri (obsidian://open?vault=<name>), name (usado en el URI), launched (bool) y registered_now (bool, True si se registro en esta llamada)"
tested: true
tests:
  - "registra si falta y construye uri sin lanzar gui"
  - "por nombre construye uri sin registrar"
test_file_path: "python/functions/obsidian/open_obsidian_vault_test.py"
file_path: "python/functions/obsidian/open_obsidian_vault.py"
---

## Ejemplo

```python
import sys, os
sys.path.insert(0, os.path.join("python", "functions"))
from obsidian import open_obsidian_vault

# Abrir por ruta: registra si falta y lanza Obsidian
res = open_obsidian_vault(
    vault="/home/enmanuel/vaults/osint",
    register_if_missing=True,
    launch=True,
    config_path="",
)
print(res["uri"])           # obsidian://open?vault=osint
print(res["registered_now"])# True si no estaba registrado

# Solo construir el URI (sin lanzar GUI, p.ej. para inspeccion o tests)
res = open_obsidian_vault("Mi Vault", launch=False)
print(res["uri"])           # obsidian://open?vault=Mi%20Vault
```

## Cuando usarla

Cuando quieras abrir un vault en la app de escritorio Obsidian desde codigo o un agente: tras crear (`create_obsidian_vault`) y registrar (`register_obsidian_vault`) un vault, esta funcion lo abre en un solo paso (registra si hace falta + lanza el URI). Para construir el URI sin lanzar la GUI, usa `launch=False`.

## Gotchas

- **Single-instance (lo importante)**: Obsidian es de instancia unica. Si ya hay una instancia corriendo con una config vieja en memoria, el URI `obsidian://open?vault=<name>` puede responder **"unable to find a vault"** para un vault recien registrado, hasta reiniciar la app. Si registras y abres en caliente, reinicia Obsidian para que recargue `obsidian.json`.
- **Lanza un proceso externo** (`xdg-open`, I/O impuro) de forma desacoplada (`start_new_session=True`, stdio a DEVNULL): no bloquea ni captura salida. `launch=False` evita lanzar nada.
- El nombre del URI es el **basename** del path (Obsidian resuelve vaults por nombre, no por ruta completa). Dos vaults con el mismo basename en rutas distintas pueden colisionar en el URI; Obsidian abrira el que tenga ese nombre en su config.
- Necesita un entorno grafico: hereda `DISPLAY`/`WAYLAND_DISPLAY` del entorno. En una sesion headless `xdg-open` puede fallar silenciosamente (el proceso se lanza pero no abre nada).
- Si `register_if_missing=True` y el vault es una ruta existente nueva, **escribe la config de la app** (via `register_obsidian_vault`, con su backup `.bak`).
