agentleFS
tboome33tboome33/obsidian-mcp-router/skills/meta-attach-vault/SKILL.md

meta-attach-vault

Skill1 starsChanged 7 months agoApache-2.0View on GitHub

Interactive DEFAULTS-FIRST wizard to attach an Obsidian vault to a code/dev workspace (the dominant case), or bootstrap a standalone local vault, or register a remote vault. If the target vault ALREADY exists in the router config, skip the wizard entirely — Step 0.0 is a one-command link-only path (`obsidian-mcp-router --attach <slug> [--also <slug>]`), no provisioning. Computes a complete default plan via `plan_vault`, shows it in one line, lets the user accept it as-is (happy path = 1 interaction) or adjust any point, then provisions in one `provision_vault` call. Use whenever the user wants to "set up Obsidian for this project", "attach a vault to this workspace", "add a vault to the router", "register a new obsidian vault", "create a wiki for this repo", "connect my remote vault" — in EN or FR. Replaces the old `meta-add-vault` skill (v0.12.7+); v2 defaults-first + MCP tools (v0.35.0+).

  • Reads credentials

The file

Show its rules and text

We split this skill into the rules it gives an agent

15 rules. About 0 are common, 7 are distinctive, and 8 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈7

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 8

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Use full-sentence description arguments on Bash: never "Run setup-vault". Always something like

    line 21
  2. Distinctive:

    Explain technical concepts in plain words: when they come up (git, .env, port allocation, plugins).

    line 22
  3. Distinctive:

    If the vault does NOT exist yet, continue with the flow detection below.

    line 49
  4. Distinctive:

    Look at the cwd and the user's message.

    line 53
  5. Distinctive:

    Use AskUserQuestion with 3 options (workspace-first recommended, standalone, remote).

    line 63
  6. Very specific:

    Check whether <cwd>/.git/ exists.

    line 73
  7. Distinctive:

    Wait for confirmation. If yes:

    line 85
  8. Very specific:

    If the user declines: warn that the .gitignore step later will still create the file but the protection isn't active until git tracks it.

    line 89
  9. Very specific:

    Call the plan_vault MCP tool (read-only, zero mutation):

    line 97
  10. Very specific:

    Call provision_vault with the accepted/adjusted answers + the automated tail:

    line 137
  11. Very specific:

    Read <cwd>/.gitignore if it exists.

    line 160
  12. Very specific:

    Use AskUserQuestion with multiSelect: true.

    line 208
  13. Distinctive:

    Ask for the vault path explicitly (no default — there's no cwd to derive from).

    line 284
  14. Very specific:

    If a remoteVaults entry with the same name already exists → ask the user before overwriting.

    line 317
  15. Distinctive:

    After everything is done, the following should be true.

    line 392

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

meta-attach-vault

Walk the user through attaching an Obsidian vault to their current context. The wizard is didactic by design — at every step it explains what's about to happen, why, and what will be touched. Built around the assumption that the user is mid-flow and shouldn't have to context-switch to read docs.

Three flows, one wizard

The wizard detects the right flow from context, but the user can override at any time.

  1. Workspace-first (the common case) — the user is in a code/dev project (cwd has .git/ or feels like a workspace) and wants a vault attached to it. The vault lives OUTSIDE the workspace (so it never gets pushed with credentials), and the workspace's .env gets a line that binds them. This is what Roland does ~95% of the time.
  2. Standalone vault (rare) — the user wants a vault that isn't tied to any code project (think personal journal). No workspace binding.
  3. Remote vault — the vault already runs on another machine (NAS, VPS, behind a tunnel) and just needs to be registered in the router config.

Style rules (apply throughout the wizard)

  1. Pre-flight every Bash call: before any Bash invocation that mutates state (provisioning, linking, gitignore edit, git init), output 2-3 lines in chat that explain: what's about to run, why, what files will be touched. This is so when the permission prompt appears, the user already has the context — they're not clicking "approve" on a cryptic command label.
  2. Use full-sentence description arguments on Bash: never "Run setup-vault". Always something like "Provisionner le vault SchoolMouv : installer 3 plugins Obsidian (Local REST API, Smart Connections, mcp-router-bridge), créer la structure wiki/wiki-meta/, enregistrer le vault dans ~/.claude/obsidian-mcp-router/config.json". Match the user's language (FR or EN — Roland is bilingual; pick from his prior turns).
  3. Explain technical concepts in plain words when they come up (git, .env, port allocation, plugins). Don't assume prior knowledge. One short paragraph is enough; don't lecture.
  4. Confirm before destructive or irreversible steps (git init, file overwrites). Provisioning a new vault into an empty directory is safe — just announce, don't ask permission.

Step 0 — Detect the flow

0.0 — FIRST: is the vault already provisioned? (the link-only fast path)

Before anything else, ask yourself whether this is a creation request at all. If the user names a vault that already exists and is already registered, there is nothing to provision — the entire job is the workspace-side binding, and it is ONE command. Do not run plan_vault/provision_vault for it.

Signals: the user says "connecte/attache ce workspace au vault X", "link this repo to my existing vault", "connect this workspace to X and Y" — or names a vault you can see in list_vaults.

Check (one call): mcp__obsidian-router__list_vaults → is the named vault in the list? If yes, run:

obsidian-mcp-router --attach <primary-slug> [--also <secondary-slug>]...

(from the workspace directory; add --workspace <path> to target another one. Fallback when the binary is not on PATH: node "<router-repo>/scripts/setup-vault.mjs" --attach <slug> ....)

That single command does the four writes and is idempotent: .env binding · .claude/settings.json (enables the router plugin — without it the .env is inert, no hook runs) · a CLAUDE.md block naming primary + secondaries · .gitignore. Then, if the vault answers (list_vaults shows it online), run the conventions picker of 1A.5 — automatically, the attach is not finished without it. Then tell the user to restart Claude Code in that workspace.

Multi-vault: the router binds ONE vault per workspace — detectVaultContext() reads a single slug. Secondaries passed via --also are documented in the generated CLAUDE.md block and reached with an explicit vault: "<slug>" on each call; they are never auto-loaded. Say this plainly to the user — the failure mode is silent (a forgotten vault: writes to the primary without any error).

⚠️ In a workspace that has never been attached, this skill is not loadable (it ships in the plugin, and the plugin is enabled by the very write above). So the CLI command is the real entry point, and this section exists for the case where the plugin is already on and the user wants to attach another vault. If you are reading this, you are in the lucky case — but still prefer the one command over re-deriving the mechanism.

If the vault does NOT exist yet, continue with the flow detection below.

0.1 — Otherwise, pick the creation flow

Look at the cwd and the user's message. Decide which flow:

  • cwd contains .obsidian/ → cwd IS a vault → standalone flow (the user wants to register this existing vault).
  • cwd contains .git/ AND no OBSIDIAN_ROUTER_DEFAULT_VAULT line in cwd's .env → workspace-first flow (default).
  • User explicitly says "remote", "QNAP", "VPS", "Cloudflare", URL pattern in their message → remote flow.
  • User explicitly says "standalone", "no workspace", "personal vault" → standalone flow.
  • Otherwise (cwd is neither a vault nor a clear workspace) → ask:

    Tu veux attacher un vault à un workspace de code (le cas courant), bootstrapper un vault standalone (sans projet associé, type journal perso), ou enregistrer un vault distant qui tourne déjà ailleurs ?

Use AskUserQuestion with 3 options (workspace-first recommended, standalone, remote).


Step 1A — Workspace-first flow

This is the dominant case. The user is in a code repo and wants documentation/notes to live in a sibling Obsidian vault that's bound to this workspace via .env.

1A.1 — Verify the workspace has git

Check whether <cwd>/.git/ exists.

If no .git/ — explain in plain words why git matters, then offer to init:

Ce workspace n'a pas de dépôt git initialisé. Avant d'aller plus loin, deux mots sur pourquoi c'est important :

  • Git versionne ton code — il garde un historique de tous tes changements, ce qui te laisse revenir en arrière si tu casses quelque chose (un fichier, une feature, une journée entière de travail).
  • Git protège tes secrets — combiné au .gitignore qu'on va créer dans un instant, il te garantit que ton .env (qui contient la clé API du vault) ne sera jamais commité ni poussé sur GitHub.
  • Git ouvre la porte au partage — push sur GitHub/GitLab pour collaborer, ou simplement pour avoir une copie de secours hors-machine.

Tu veux que je lance git init dans ce workspace maintenant ?

Wait for confirmation. If yes:

  • Pre-flight: "Je lance git init dans <cwd> — ça crée un dossier .git/ qui suit tes changements. Aucun fichier de ton code ne sera modifié."
  • Bash with description: "Initialiser un dépôt git dans le workspace courant (crée .git/, ne touche à aucun fichier existant)".

If the user declines: warn that the .gitignore step later will still create the file but the protection isn't active until git tracks it. Continue.

1A.2 — Compute the plan (DEFAULTS-FIRST) with plan_vault, then adjust

The v2 wizard is defaults-first: instead of asking every question up front, it computes a complete default plan, shows it in ONE line, and lets the user accept it as-is (happy path = 1 interaction) or adjust any single point.

Propose a default vault path: C:\VAULTS\<basename-cwd-as-is> (Windows) or ~/VAULTS/<basename-cwd-as-is> (POSIX) — HORS du workspace so the vault's .env (API key) never lands in the code repo. Preserve the basename exactly as-is (case, version suffixes).

Call the plan_vault MCP tool (read-only, zero mutation):

mcp__obsidian-router__plan_vault({ path: "<default-vault-path>", linkWorkspace: "<cwd>" })

It returns defaults (name, slug, path, source, plugins profile + resolved list, wikiMode, theme), questions (option lists — the 5 wiki modes each with an explanation, the themes installed in the source, the copyable vaults, the plugin profiles), warnings, and steps.

Fallback (older router / gated deployment where the tools are hidden): run the engine directly — node "<router-repo>/scripts/setup-vault.mjs" "<vault-path>" --link-workspace "<cwd>" --dry-run --json — and parse the SAME plan shape. Resolve <router-repo> from ${CLAUDE_PLUGIN_ROOT}, or ~/.claude/plugins/marketplaces/obsidian-mcp-router-marketplace/, or ask.

Present the plan as a ONE-LINER (match the user's language):

Plan proposé : vault « <name> » → <path> · source : <source.kind> · plugins : profil <profile> (<n>) · thème : <theme|défaut> · mode wiki : <wikiMode.mode> · slash commands workspace : oui (~10k tokens/session)

OK tel quel, ou tu veux ajuster quelque chose ? (nom · emplacement · source · plugins · thème · mode wiki)

Surface any warnings right here (slug collision, path outside known roots → the user must confirm allowOutsideRoots, etc.).

If the user wants to adjust — each point is individually adjustable. Use AskUserQuestion with the option lists straight from plan_vault's questions (they already carry descriptions + which is the default):

  • Wiki mode — present ALL 5 with their explanations (questions.wikiMode.options): 🧠 personal · 🔬 research · 💼 business · 💻 code · 🎯 domain. For domain, ask the user to describe the domain in one line, then translate it into a flat section list YOURSELF and pass it as wikiMode.sections — the engine stays 100% deterministic, it only lays out your sections.
  • Source — reference (default) · copy config from an existing vault (questions.source lists the copyable vaults; config-only, secrets regenerated) · fresh skeleton · bare.
  • Plugins — recommended (default = the source's full set) · minimal · custom.
  • Theme — pick from questions.theme.options. ⚠️ --theme is currently recorded but NOT applied (Lot 2 chantier) — tell the user their pick is noted but the theme change lands in a later release.

Re-run plan_vault with the adjusted args to show the updated one-liner, then proceed once the user is happy.

1A.3 — Provision in ONE call with provision_vault

Pre-flight (in chat, before the call) — explain the concrete effects:

Je provisionne le vault en un seul appel. Concrètement :

  1. Créer le dossier à <vault-path> (si absent).
  2. Installer les plugins en clonant depuis la source : Local REST API (l'API HTTP du router), MCP Router Bridge (les routes /open cliquables), + le profil choisi (Smart Connections, Templater, …).
  3. Allouer un port HTTPS unique (+ un port HTTP +10 pour les liens qui contournent Bitdefender) et générer une clé API fraîche.
  4. Scaffolder wiki/, wiki/sessions/, wiki-meta/{index,hot,overview,log}.md (mode wiki choisi).
  5. Écrire <vault>/.env + <vault>/.mcp.json, enregistrer dans ~/.claude/obsidian-mcp-router/config.json, lier le workspace (OBSIDIAN_ROUTER_DEFAULT_VAULT dans <cwd>/.env) et activer les slash commands du workspace.
  6. Ouvrir Obsidian sur le vault + sonder la santé REST.

Call provision_vault with the accepted/adjusted answers + the automated tail:

mcp__obsidian-router__provision_vault({
  path: "<vault-path>", linkWorkspace: "<cwd>", claudeWorkspace: true,
  source: { kind: "<...>", fromVault: "<...>" }, plugins: { profile: "<...>" },
  wikiMode: { mode: "<...>", sections: [ ... ] },
  open: true, probe: true
})

It returns a step-by-step report + port, insecurePort, openUri, probeResult. open: true launches Obsidian on the new vault; probe: true polls the REST port for a health verdict (expected red until the user clicks "Trust author and enable plugins" — that's the one incompressible manual gesture).

Fallback (no tools): node "<router-repo>/scripts/setup-vault.mjs" "<vault-path>" --link-workspace "<cwd>" --claude-workspace <adjusted-flags> --open --probe. Bash description: full sentence listing the effects (plugins, port, key, wiki scaffold, .env/.mcp.json, registry, workspace link, open, probe).

Show the user the step report (port allocated, slug, plugins) + the probe verdict: ✅ reachable, or 🔴 "pas encore joignable — clique Trust author dans Obsidian puis je relance la sonde". NOT the full raw output.

1A.4 — Edit the workspace .gitignore

Pre-flight:

Dernière étape de la configuration : je m'assure que <cwd>/.gitignore contient bien .env et .mcp.json, sinon ces fichiers risqueraient d'être commités (et avec eux, indirectement, le slug du vault — pas critique mais pas idéal). C'est idempotent : si les lignes sont déjà là, je ne touche à rien.

Read <cwd>/.gitignore if it exists. Use Edit (or Write if absent) to append .env and .mcp.json under a # obsidian-mcp-router marker comment, ONLY if those lines aren't already present. Use this format:

# obsidian-mcp-router (added by meta-attach-vault)
.env
.mcp.json

Idempotency rule: scan existing content for the exact strings .env and .mcp.json on their own lines BEFORE appending. If both already present, skip silently.

1A.5 — Conventions picker (AUTOMATIC at the end of every attach)

This step is not optional and not "offered" — it RUNS at the end of every flow that leaves a vault attached: 1A after provisioning, 1B, and the 0.0 fast path once the vault answers. Do not ask "do you want the conventions picker?" — show the picker itself. The only precondition is a reachable vault: install_conventions goes through the vault's REST API, so if the probe is still red (Trust author not clicked yet), say so, wait for the user to confirm the click, re-probe, then run it. If the vault stays unreachable, go to the last paragraph of this section (name what is missing).

READ THE TARGET FIRST — the picker is not allowed to guess. A vault provisioned from the reference template already carries the four CORE conventions — roadmap-discipline, default-vault-health-check, wiki-query-first, path-disambiguation (decision [[conventions-livrees-par-le-modele]], 2026-09-11; that is the reference .template VAULT, not the repository's templates/ files, which carry no library convention at all). Before composing the question, ask the router for the real state, in one call that writes nothing:

install_conventions({ vault: "<slug>", ids: [], dryRun: true })

It resolves the vault's conventions file (path, fileExisted), and returns catalogue (every convention the library ships, id + heading) and detection (installed / duplicate, per convention). If it refuses because two conventions files exist, stop and ask the user which one is theirs — do not pick one.

Measured on 0.94.1 (2026-09-11, vault La méthode LICARES): the picker was shown blind, the user kept six conventions and unchecked two — and all eight were already installed. Every positive choice was a no-op reported as a success, and both negative choices were violated in silence. One of them, auto-enrichment, governs automatic saves into the vault.

Pre-flight (adapt the counts to what you actually detected):

Le vault est provisionné et lié au workspace. Reste à choisir quelles conventions doivent figurer dans le fichier de conventions du vault (<le path que le dryRun a renvoyé>). Une convention, c'est une règle de comportement pour Claude — par exemple "toujours mettre à jour les roadmaps quand on ship du code" ou "vérifier dans le wiki avant de répondre". Elles sont lues au démarrage de chaque session sur ce vault.

⚠️ Ce vault en porte déjà N sur M. Les autres sont proposées, déjà cochées : tu décoches ce que tu ne veux pas. Décocher une convention déjà présente veut dire retirer sa section de ce fichier — je te le redemanderai avant d'y toucher.

M is the number of options you are about to display, counted from the catalogue the dryRun returned — never a literal number written on this page.

The initialization rule is ASYMMETRIC, and that is the whole point

état détectépré-cochée ?ce que le défaut propose
présentetoujoursne rien toucher
absente, recommandéeouil'installer — visible, refusable
absente, non recommandéenonrien

A default may propose an installation. It may never propose a removal. That is not a convenience, it is the guard: since v0.94.3, un-checking a PRESENT convention means removing it, so a default that un-checked an installed convention would be asking a deletion question nobody asked for. Applying the recommended list in the un-checking direction is exactly that bug — an adversarial round found it in the first version of the code.

In the other direction there is no such danger: pre-checking an absent convention proposes an install the user can refuse in one click.

Why the absent ones arrive checked (decision [[conventions-livrees-par-le-modele]] §2): the reference template stopped shipping the stylistic conventions, and a feature nobody knows about is a feature nobody ever enables. The user must act to refuse, not to discover. If they validate without changing anything, they get the same result as before the decision — the difference is that it was shown to them.

Display the whole library, not a subset. Show every convention in the dryRun's catalogue that is not flagged retired: true (a retired one is recognised, never offered — see 1A.5's bilingual note; split over several AskUserQuestion questions if one cannot hold them all); the collection you display IS the collection you plan with. Planning with a wider list than you displayed puts a convention the user never saw into the remove bucket, and the confirmation then says "you did not check these" about a checkbox that never existed.

Use AskUserQuestion with multiSelect: true. Pre-check per the table above, suffix a detected one with — déjà en place, and give each option a description that says what it DOES. The recommended set — the nine below — and the wording that survived review:

  • roadmap-discipline — tenir les roadmaps à jour quand du code est livré
  • default-vault-health-check — prévenir si le vault par défaut n'est pas joignable, et ne jamais retomber sur le système de fichiers
  • wiki-query-first — consulter le wiki AVANT de répondre à une question de fond
  • path-disambiguation — ne jamais confondre le path du workspace et celui du vault
  • source-type — tracer d'où vient une page (source_type: en frontmatter)
  • languages — la ou les langues des pages de ce vault (une seule : tout dans cette langue ; plusieurs : une section par langue) — la valeur est demandée juste après
  • heading-hierarchy — structure de titres imposée, et contrat de frontmatter sur les pages de décision
  • auto-enrichment — Claude propose de sauvegarder les décisions et résultats au fil de la conversation (il demande toujours avant d'écrire), et marque une pause quand tu changes de sujet
  • description-frontmatter — comment bien écrire la phrase description: (le champ, lui, est requis de toute façon)

description-frontmatter n'est pas un choix de comportement comme les huit autres, et son étiquette doit le dire avant que l'utilisateur coche ou décoche, pas après. Ce qu'il installe, c'est le guide de rédaction : quoi dire, quelle longueur, comment citer la valeur. Le champ lui-même est exigé indépendamment — le lint du wiki signale chaque page sans description depuis la v0.59.2, la régénération des projections OKF les reporte, et les index publient la phrase telle quelle. Cette exigence-là part avec chaque vault scaffoldé, dans le gabarit, sans passer par ce menu.

Donc : décocher cette case ne rend rien optionnel, et ne retire rien d'un vault qui la porte déjà — ça renonce seulement au guide. Dis-le dans ces termes. Mesuré le 2026-09-11 : aucun des 16 vaults inspectés ayant un fichier de conventions ne contenait cette section, alors que le lint s'appliquait à leurs pages.

languages is the one option with a value (decision [[convention-languages-remplace-bilingual]], 2026-09-26 — it replaced the pre-checked bilingual box). When it lands in the install bucket, ask ONE more question before installing it:

Langues du vault ? (codes ISO 639-1, la langue principale d'abord — fr par défaut ; par exemple fr, fr, en, en)

An empty answer is fr. Install it with that value (/obsidian-router:conventions install languages renders the snippet with it — never the raw snippet, whose <languages> placeholder declares nothing). A value parseLanguagesValue refuses (français, fr-FR) is asked again, never guessed. When the vault ALREADY carries languages, show its current value beside the option (— déjà en place : fr, en) and do not ask again. A vault that still carries the retired bilingual shows it as « bilingual — retirée, à migrer vers languages »: it is not in the menu (the picker globs snippets/, and bilingual lives in retired/), so offer the migration (/obsidian-router:conventions migrate-bilingual) instead of a checkbox — and never read its absence from the menu as a removal the user asked for.

The auto-enrichment line above is deliberate and was corrected on 2026-09-11: "règles d'enrichissement automatique (4 modes)" warned the user of nothing. The convention grants no write permission — the mode defaults to ClaudeAsk, which always asks — but it DOES change the shape of every conversation, and that is what the description has to say.

The first four are shipped by the reference template, so on a template-born vault they arrive detected. Any absent convention outside the recommended set is displayed unchecked: visible, so it exists for the user, without being proposed.

The word "absent" there is load-bearing, and review caught its absence. Written without it, that sentence contradicts the table one paragraph above: a convention the vault ALREADY carries but that nobody recommended would be displayed unchecked, and unchecking a present convention is what puts it in the remove bucket. The default would then propose exactly the deletion the asymmetric rule exists to forbid. Detection wins over the recommended list, always: present means pre-checked, whatever the list says.

Then plan the answer, don't act on it directly. Sort the displayed options against the dryRun's detection into install (checked, absent) / keep (checked, present) / remove (unchecked, present) / skip (unchecked, absent) — the rule planConventionPicker implements. Act on each bucket as the conventions skill's pick section specifies:

  • install — ONE call for the whole bucket: install_conventions({ vault: "<slug>", ids: [<every id of the bucket>] }). The router reads the texts from its own package, appends them in one compare-and-swap write (so it works on a shared vault), and reads the file back. Never paste a snippet, and never use append_to_file for this — it carries no precondition and the shared-vault gate refuses it. Then show the verified result: installed, alreadyPresent (say "déjà en place"), unknown, and verified — if verified is false, show problems and say the install is NOT confirmed. Link the file with the returned clickToOpenUrl. A conflict (409) means the file moved under you and nothing was written: run the same call again.
  • keep — report "déjà en place". Never as "installée".
  • remove — ask before anything is cut, listing them by name and saying what disappears; on a yes, go through /obsidian-router:conventions remove <id> with its preview, sidecar backup and verifyRemoval check; on a no, say that leurs sections restent dans ce fichier. Say "je retire leur section de ce fichier", not "je les désactive": several of these also live in the user's global ~/.claude/CLAUDE.md, where this changes nothing — and whether a rule is active depends on which files the next session loads, which nothing here observes.
  • skip — nothing, silently. This is the only bucket that may be silent.

Print the plan line before acting (prévu : N à installer, M déjà en place, R décochées mais présentes (confirmation avant retrait), S non touchées) — it counts intentions. Then close with a summary built from what actually HAPPENED: installed, already in place, removed, declined, failed. If nothing was installed because everything was already there, the first line must say so: "0 installée, 6 déjà en place" is the truth, "6 conventions configurées" is not.

If the picker was skipped, NAME what is missing. Impatience, a non-interactive run, a user who says "plus tard" — the flow can reach the recap without the question ever being answered. The recap must then list the conventions that are not installed and the command that adds them:

Conventions non installées : languages, heading-hierarchy, auto-enrichment — /obsidian-router:conventions install <id> quand tu veux.

A missing feature that is named is a choice deferred; a missing feature that is silent is a feature that will never exist for its owner. That is the failure mode the whole decision is built against (decision [[conventions-livrees-par-le-modele]] §4), and it is the one case the pre-checking cannot cover on its own.

1A.6 — Final reminders

Before composing the recap, call mcp__obsidian-router__list_vaults once to get defaultVaultStatus (or look up the newly-attached vault by slug in the vaults[] array). Use its openUri field for the clickable Obsidian link — it's pre-encoded for spaces/accents and ships in router v0.10.0+. Do NOT compose the obsidian:// URI by hand: vault names with spaces or accents (e.g. opsidian-mcp-router et bridge) need proper URL-encoding that's easy to get wrong.

End with a short recap (FR or EN matching the user). provision_vault with open: true already launched Obsidian and probe: true already ran the health check, so the recap reflects that:

✅ Vault <slug> attaché au workspace <cwd-basename>. Obsidian a été ouvert automatiquement sur le vault.

Le geste incompressible qui reste :

  1. Dans Obsidian, clique « Trust author and enable plugins » — sans ça, le serveur Local REST API ne démarre pas et le router ne peut rien lire ni écrire. (La sonde a dit : <probeResult ✅ joignable | 🔴 pas encore — c'est normal avant le Trust author>.)
  2. Redémarre Claude Code dans ce workspace pour que le router charge le nouveau vault et que le hot-cache active le mode workspace-bound.

Si la sonde était rouge : une fois « Trust author » cliqué, je peux relancer provision_vault en mode probe seul (ou /obsidian-router:meta-audit-bridge-readiness) pour confirmer le vert.

Conventions installées : <installed> · déjà en place : <alreadyPresent> · vérifié : <oui|non> — dans <path renvoyé par install_conventions> (lien : clickToOpenUrl).

Pour vérifier que tout est bien câblé : /obsidian-router:meta-status (diagnostic complet) ou /obsidian-router:discover-list-vaults (liste rapide).

If provision_vault returned a path-outside-known-roots / no-known-roots refusal, DON'T silently retry with allowOutsideRoots — surface it: "le chemin <path> est hors des racines de vaults connues ; tu confirmes que je crée le vault là quand même ?" and only pass allowOutsideRoots: true after the user says yes.


Step 1B — Standalone vault flow

The rare case: a vault that isn't tied to any workspace (like Roland's personal journal vault).

Same as 1A but:

  • Skip the git step entirely (no workspace = no git concerns at this layer).
  • Skip the linking step (no workspace to bind).
  • Skip the workspace .gitignore edit.
  • Still scaffold the wiki structure and run the conventions picker (1A.5, automatic) — even a personal vault benefits from them.

Ask for the vault path explicitly (no default — there's no cwd to derive from).


Step 1C — Remote vault flow

The vault already runs elsewhere (NAS, VPS, behind Cloudflare Tunnel). Only registration is needed.

Required from the user (ask only what's missing):

  1. name — short identifier used everywhere (e.g. qnap, vps-research, tradingview-tunnel). Lowercase, no spaces.
  2. baseUrl — the HTTPS URL where the remote Obsidian Local REST API is reachable. Examples:
    • https://192.168.0.11:27125 (LAN)
    • https://qnap.tailnet.local:27125 (Tailscale)
    • https://vault.mydomain.com (Cloudflare Tunnel with custom domain)
  3. apiKey — the Local REST API key from the vault's data.json on the remote machine. The user fetches it themselves:
    • Open the remote vault in Obsidian on its host
    • Settings → Community plugins → Local REST API
    • Copy the API Key field

Optional:

  1. tlsInsecure (default true for localhost/LAN, false otherwise) — only true for self-signed certs in trusted networks.
  2. timeoutMs (default 10000) — bump to 15-20s if the link is slow.
  3. extraHeaders — for vaults behind Cloudflare Access with a service token. Two values needed:

Edit the config

  1. Read ~/.claude/obsidian-mcp-router/config.json.
  2. Parse the JSON.
  3. If a remoteVaults entry with the same name already exists → ask the user before overwriting.
  4. Append (or replace) the entry in the remoteVaults array.
  5. Write atomically.
  6. Confirm:
    • The path edited
    • The vault name added
    • That a Claude Code restart is required to pick up the change

Optional: live verification

curl -sk -H "Authorization: Bearer <apiKey>" \
  [-H "CF-Access-Client-Id: ..."] [-H "CF-Access-Client-Secret: ..."] \
  "<baseUrl>/" | head -5

Returns server-info JSON → golden. 401 → wrong API key. Timeout → URL unreachable.

Then: attach it to the workspace, and finish it — in this order, without skipping

Registration alone leaves a blank remote vault with nothing but Local REST API. Measured on a real attach (a linuxserver container): no bridge, no wiki, no conventions, and nothing said so. The chain below is the whole job; each step's output says whether the next one is needed.

  1. Attach, from the workspace, in a shell: obsidian-mcp-router --attach <name> --local-path <abs-dir> — --local-path only if the vault's files ALSO sit on this machine (a container's bind mount, for instance). The directory is checked against the vault over REST before it is recorded; a mismatch refuses with nothing written. It buys the hot-cache hook, index freshness for semantic search, and the two plugin commands below. The command ends with "État final / Final state" and an ordered next steps list. Read it out to the user as it is; do not paraphrase it into a shorter plan, and follow ITS order — it is not always the order below. A blank vault is the case that differs: its folder cannot be verified yet (the check compares a note served over REST with the same file on disk, and a blank vault has no note), so --local-path is not recorded, and the list puts the wiki first (written over REST, no disk needed), then "attach again with --local-path", then the plugins.
  2. Plugins (next steps 1–2, when listed): run obsidian-mcp-router --install-plugins <name> --dry-run, show the plan plugin by plugin, and ask before applying it with the --approved-plan-sha256 it printed — it downloads third-party code from the official registry, so the user authorizes that exact plan. Then have the user reload Obsidian (desktop: Ctrl+P → "Reload app without saving"; container: the same command in the web UI, or docker compose restart) and turn Restricted mode off. Verify with obsidian-mcp-router --plugin-health <name>: every expected plugin must be with code, enabled and loaded, and the bridge installed. "Enabled without code" or "bridge absent" is not done. Without --local-path, both commands refuse: the user installs from Obsidian's Community plugins screen instead, and --plugin-health cannot vouch for it — say so.
  3. Wiki (when "catalog: no"): run the wiki skill on this vault.
  4. Conventions: the picker of 1A.5 runs automatically at the end of the wiki skill; if the wiki already existed, run it now. It installs with ONE install_conventions call.
  5. Re-run step 1's command (same arguments — it is idempotent) and report its final state. The attach is finished when it prints ready yes; until then, name what is still missing. A ready yes may be followed by an optional block (the conventions picker, when the owner declined a recommended convention or has not chosen yet): that is an offer to repeat once, not a step that keeps the attach open — say it, and stop.

Anti-patterns (apply across all flows)

  • Don't run the creation wizard on a vault that already exists — if it is in list_vaults, the answer is --attach (Step 0.0), one command. Running plan_vault/provision_vault against an existing vault path is slow, alarming, and wrong.
  • Don't re-derive the binding mechanism from the router source — reading config.json, grepping for OBSIDIAN_ROUTER_DEFAULT_VAULT, opening hooks/_helpers/workspace-vault.mjs. That investigation is exactly what --attach exists to make unnecessary. (It happened on 2026-08-02: ~15 tool calls for what is four file writes.)
  • Don't write .env and call the workspace attached — without .claude/settings.json, the plugin stays off and the binding has no effect. Use --attach, or --link-workspace --claude-workspace if you truly want only the low-level step.
  • Don't run any Bash without a pre-flight explanation — the user sees the permission prompt and the description; both must make sense without prior context.
  • Don't bury the explanation in long paragraphs — 2-3 lines per pre-flight, in plain words. Roland is technical but tired; respect his time.
  • Don't write secrets (API keys, service token secrets) anywhere except ~/.claude/obsidian-mcp-router/config.json and the vault's own .env. No log files, no echo to terminal beyond the immediate confirmation, no clipboard write.
  • Don't auto-restart Claude or Obsidian — tell the user to do it themselves.
  • Don't add a remote vault entry without a full set of name, baseUrl, apiKey — refuse and ask for the missing fields.
  • Don't pretend the setup-vault.mjs script exists if it doesn't — fall back to the manual path with a clear explanation.
  • Don't create the vault INSIDE the workspace — that defeats the credential-protection goal. Default vault path is C:\VAULTS\<basename> (or ~/VAULTS/<basename>), never <cwd>/vault/.
  • Don't skip the conventions picker silently — even if the user looks impatient, the picker is one AskUserQuestion call. It's the cheapest way to materialize the global rules locally.
  • Don't show the conventions picker before reading the vault's CLAUDE.md — a blind picker asks the user to choose things that are already there, and turns their "no" into nothing at all. Detect first, pre-check what is installed, and treat an unchecked-but-present convention as a question, never as silence.

Quick test (sanity-check after end-to-end run)

After everything is done, the following should be true. If any of them isn't, surface it:

  • <vault>/.obsidian/plugins/obsidian-local-rest-api/data.json exists
  • <vault>/.mcp.json exists and references the router binary
  • <vault>/wiki-meta/catalog.md exists (otherwise --link-workspace would have refused)
  • <cwd>/.env contains OBSIDIAN_ROUTER_DEFAULT_VAULT="<slug>"
  • <cwd>/.gitignore contains .env and .mcp.json
  • ~/.claude/obsidian-mcp-router/config.json has <vault-path> in portRegistry
  • the vault's conventions file (the one resolveClaudeMd picked — often Documentation/CLAUDE.md, not the root) contains the H2 headings of the conventions the user kept, and none of the ones they asked to remove

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.