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

meta-status

Skill1 starsChanged 7 months agoApache-2.0View on GitHub

Diagnose the obsidian-mcp-router and all its configured vaults. Pings each vault, reports online/offline/auth status, and suggests fixes for each issue type. Use when the user says "check vault status", "diagnose the router", "are my vaults reachable", "status of obsidian", "what's wrong with the router", or asks to debug an obsidian connection issue.

  • Reads credentials

The file

We split this skill into the rules it gives an agent

11 rules. About 0 are common, 6 are distinctive, and 5 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈6

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 5

    Very specific

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

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

    Call the router's list_vaults tool (no arguments).

    line 12
  2. Distinctive:

    Use ✅ for online, ❌ for offline, ⚠️ for missingApiKey or any partial issue

    line 43
  3. Very specific:

    Check verified BEFORE available — the two rules below used to be written in the other order, so MARKITDOWN_PATH=markitdown.exe (available, …

    line 95
  4. Very specific:

    EVERY list_vaults response, including the automatic one the default-vault health-check convention makes at session start — it is data, …

    line 153
  5. Distinctive:

    Don't try to fix issues automatically — this skill is a diagnostic, not a fixer.

    line 208
  6. Very specific:

    Don't run --install-plugins without its --dry-run first, and don't apply a plan the user has not seen and approved — it downloads …

    line 210
  7. Distinctive:

    Don't expose API keys in the output — nor the view agent's token: report its source, never read the token file or the agent's host to show …

    line 211
  8. Distinctive:

    Don't write the Claude Code settings or a server declaration to configure the view agent: show the user the lines and where they go, and …

    line 212
  9. Distinctive:

    Don't dump the full raw JSON to the user — render the table and the issue blocks.

    line 213
  10. Distinctive:

    Don't run write/delete tools as part of this skill.

    line 214
  11. Very specific:

    If list_vaults itself errors out (e.g., the router process crashed, MCP connection dead), report that distinctly:

    line 218

≈ “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-status

Produces a one-shot diagnostic of the multi-vault Obsidian router. Run it when the user wants to know what's working, what isn't, and how to fix it.

Steps

  1. Call the router's list_vaults tool (no arguments). The router will ping each configured vault in parallel and return a structure like:
    {
      "defaultVault": "tradingview",
      "configPath": "/Users/.../.claude/obsidian-mcp-router/config.json",
      "vaults": [
        {
          "name": "tradingview",
          "type": "local",
          "baseUrl": "https://127.0.0.1:27125",
          "online": true,
          "latencyMs": 4,
          "missingApiKey": false,
          "isDefault": true
        },
        {
          "name": "qnap",
          "type": "remote",
          "baseUrl": "https://qnap.tailnet.local:27125",
          "online": false,
          "latencyMs": 5012,
          "error": "[qnap] timed out after 5000ms calling /",
          "missingApiKey": false
        }
      ]
    }
  2. Render the result as a compact summary:
    • First line: <n> vault(s) configured · <m> online · default: <name>
    • Then a markdown table with columns: name | type | status | latency | path/baseUrl
    • Use ✅ for online, ❌ for offline, ⚠️ for missingApiKey or any partial issue
  3. For each vault that is NOT fully healthy, add a short diagnostic block explaining the likely cause and the fix:
SymptomLikely causeFix to suggest
online: false AND type: localObsidian not running on this vault, or a different vault is openOpen Obsidian and load the vault at the path shown
online: false AND type: remote AND error includes "unreachable"Remote host not reachableCheck that the remote machine is online, the tunnel is up (Tailscale / Cloudflare), and that no firewall changed
online: false AND error includes "timed out"Network path is alive but slow, or the remote vault is busyBump timeoutMs for that vault to 15000-20000
online: false AND error includes "401"API key is wrong or expiredFor local: re-run setup-vault.mjs to regenerate. For remote: re-fetch the key from the host's data.json
online: false AND error includes "cf_access" or "cloudflareaccess.com"Cloudflare Access policy is blocking the requestVerify extraHeaders has the right CF-Access-Client-Id + CF-Access-Client-Secret and that the service token is attached to a "Service Auth" policy on the Access app
missingApiKey: true AND type: localLocal REST API plugin never enabled for this vault, so no data.json to readOpen Obsidian on this vault, enable Local REST API plugin, then re-run setup-vault.mjs
online: true AND latencyMs > 500 AND type: remoteFunctional but slow; might cause timeouts on large operationsNote it as a soft warning; consider Tailscale Funnel for a closer relay or moving to a Cloudflare Tunnel
  1. Check the plugins of each vault that has a disk, with the CLI — list_vaults answers "is the REST API reachable", not "does the vault have its plugins". A vault can list a plugin as enabled and have no code for it (a skeleton cloned without binaries, a settings-only sync), and Obsidian then shows nothing at all. For every type: local vault — and every remote vault that declares a localPath — run:

    obsidian-mcp-router --plugin-health "<vault name>" --json

    It is read-only: it reads .obsidian/ and, when the REST API answers, calls GET /commands/ and probes the bridge's click-to-open route (/mcp-router-bridge/open/, then /open/). Exit code 0 = the required plugins (Local REST API, the bridge) have code; 1 = one of them is missing, settings only, or enabled without code; 2 = the vault has no disk reachable from here (a remote vault without localPath) — say that in one line, it is not a plugin fault.

    From the JSON, report per vault:

    • enabledWithoutCode non-empty → ⚠️ <vault>: enabled without code — <ids>.
    • bridge is absent or settings-only → ⚠️ <vault>: bridge <state> — click-to-open links will not work.
    • each entry of problems → its message, then its fix verbatim. A soft problem (no command seen, click-to-open route not registered) is a hint to reload Obsidian or turn Restricted mode off, not a missing plugin — say so.
    • a live.error → the live half did not run (Obsidian closed, key rejected); the disk verdict still stands. Never turn "not probed" into "not loaded".

    The fix for missing code is obsidian-mcp-router --install-plugins "<vault>" --dry-run followed by an apply with the printed approvedPlanSha256. That command downloads third-party code: offer it, show the dry-run plan, and run the apply only after the user says yes to that plan (see Don't). After an install, Obsidian must be reloaded (Ctrl+P → "Reload app without saving") with Restricted mode off.

  2. Report the conversion toolbox, from the conversionToolbox field of the same list_vaults response. Eight tools go through the markitdown Python CLI, which is installed by an explicit opt-in and never automatically — so on a fresh install they are dormant, and nothing else says so until the first call fails mid-task. One line, after the vault table:

    Check verified BEFORE available — the two rules below used to be written in the other order, so MARKITDOWN_PATH=markitdown.exe (available, unverified) matched both "say ready and nothing more" and "never say ready", and which one won was undefined.

    • available: true and verified: true → ✅ Conversion toolbox: ready (<via>) where via is bundled-venv, env-override or path. Say nothing more.
    • available: true and verified: false → ○ Conversion toolbox: configured (<via>), not verified. The answer was taken on the user's word rather than measured: a bare command name that execFile resolves through PATH at call time, or a UNC path that is unsafe to stat on this hot path. Do not upgrade it to "ready", and do not offer to install anything — nothing says it is missing.
    • available: false and optedOut: true → ○ Conversion toolbox: off by choice (OBSIDIAN_ROUTER_SKIP_MARKITDOWN=1). Do not suggest installing it — the user already answered that question.
    • available: false and verified: false and optedOut: false → the probe could not answer at all (it never throws; this is how it reports that). Say ? Conversion toolbox: state unknown — the check could not run. Do not say "not installed", and do not offer an install: nothing was measured, so absence was never established.

      (Test optedOut first, above — an opted-out machine with nothing installed also has hint: null, so keying "unknown" on a null hint made the two rules overlap. verified is the field that separates them: the opted-out case still measured.)

    • available: false, optedOut: false and via: "env-override" → this is NOT "not installed". MARKITDOWN_PATH is set and points at something that will not run, which masks any working bundled venv or PATH install underneath. Say ⚠️ Conversion toolbox: MARKITDOWN_PATH points at something unusable, then quote the hint verbatim — it names the offending value and says to fix or unset the variable. Do not offer to install anything: nothing is missing.
    • available: false, optedOut: false, verified: true, any other via → ⚠️ Conversion toolbox: not installed — 8 tools dormant, then quote the hint field verbatim: it carries the exact command for THIS install, which a generic "run it in the router directory" does not for a plugin-cache install. Offer to run it; do not run it unasked (see Don't).

    Do not inflate the count — and do not over-reassure either. toolsAffected and toolsDegraded in the response are the two lists; read them rather than counting from memory. git_repo_to_markdown never used markitdown at all (it goes through repomix). youtube_to_markdown falls back to yt-dlp captions, which keeps it working only if yt-dlp is installed — itself another executable the router does not install, so on a genuinely fresh machine it can fail too.

    The yt-dlp state is measured, so read it — do not assume it. toolsDegraded is computed: it lists youtube_to_markdown exactly when conversionToolbox.youtube.ytdlp is missing (or unknown, when the check could not run), whatever markitdown's state — the transcript only ever comes from yt-dlp. Render it as its own line: found → ✅ yt-dlp: found (add "taken from YTDLP_PATH, not checked" when youtube.verified is false); missing → ⚠️ yt-dlp: not found — youtube_to_markdown degraded, then quote youtube.hint verbatim (it names the no-admin install, uv tool install "yt-dlp[default,curl-cffi]", or the broken YTDLP_PATH); unknown → ❔ yt-dlp: state unknown. If the user reports YouTube refusing the machine (HTTP 429, "Sign in to confirm you're not a bot"), the fix is YTDLP_COOKIES (absolute path to a Netscape cookies.txt) or YTDLP_PROXY set in the MCP server declaration — never in a workspace .env, which does not accept them.

    Where the state travels vs. where you surface it. conversionToolbox rides on EVERY list_vaults response, including the automatic one the default-vault health-check convention makes at session start — it is data, cheap, and always there. Surfacing it is this skill's job: do not raise it unprompted at session start, and do not mention it in an unrelated answer just because you saw the field.

    ONE OFFER PER CONVERSATION. optedOut records only the permanent env-var answer; a spoken "not now" is written down nowhere, so nothing in the response stops you asking again. If the user has already declined in this conversation — here or in meta-setup — report the state in one line and do not re-offer. Mention OBSIDIAN_ROUTER_SKIP_MARKITDOWN=1 once, as the way to make the answer stick across sessions, and then let it go. Repeating the offer is the pressure this feature exists to avoid.

5b. Report read links for remote vaults, from the viewAgent field and each vault's readLink in the same list_vaults response. A remote vault has no local click-to-open link (unless it declares insecurePort); its read link comes from a view agent, and a router started without one hides get_view_link — the state a session once read as "this vault has no link".

  • No type: "remote" vault in vaults[] → say nothing.
  • viewAgent.hint non-null → ⚠️ Read links: <hint>, quoted verbatim — it names the variables, where they go (the MCP server's environment: its declaration's env, or the env block of the Claude Code settings) and that a workspace .env refuses them. Add that a new session is needed afterwards for get_view_link to appear. Do not offer to edit the settings or to read the agent's token yourself: that is the user's call (see Don't).
  • viewAgent.configured: true and viewAgent.health: "ok" → ✅ View agent: <url> (token: <token>) — token is the SOURCE (file, env, none), never a value. Add · token inline — prefer OBSIDIAN_ROUTER_VIEW_AGENT_TOKEN_FILE when it is env.
  • Any vault whose readLink.available is false → ⚠️ <vault>: no read link — <readLink.hint>.
  • readLink.agentListsVault: false with available: true → a soft note, not an issue: the agent serves the vault only if it accepts vault hints.

4b. Report which router build answers, and whether this session's hooks ran — the routerBuild and sessionHooks fields of the same response. Two lines:

  • Router build: <version> · fingerprint <fingerprint> — the version string alone names every commit since the last release (the plugin installs from main); the fingerprint names the server and hook code (not the skills' text), and the repository script scripts/identify-build.mjs, given it in a clone names the commit. Add · git <gitHead> when present.
  • sessionHooks.status: observed → Hooks: ran. absent-from-plugin → ⚠️ quote the message verbatim: this copy of the plugin has no hooks/hooks.json, so hot.md, the decisions recall and the briefing never reached this session. not-observed → ⚠️ quote the message verbatim. not-yet-observed → say it is too early to tell. Never say "hot.md is loaded" when the status is not observed.
  1. End with one of two endings:
  • All healthy:

    🎉 All <n> vaults online. Ready to use.

  • Issues present:

    Found <k> issue(s). Apply the fixes above, then re-run meta-status to verify.

Don't

  • Don't try to fix issues automatically — this skill is a diagnostic, not a fixer. Surface the problem and let the user choose how to proceed.
  • Don't install markitdown on your own initiative, even if the user says "fix the issues". It is a 30-180 s download of ~100 MB of Python wheels, and the router's refusal to impose a Python install is a written decision, not an oversight. Offer, wait for a yes, then run it.
  • Don't run --install-plugins without its --dry-run first, and don't apply a plan the user has not seen and approved — it downloads third-party code into their vault. --plugin-health is the only plugin command this diagnostic runs on its own.
  • Don't expose API keys in the output — nor the view agent's token: report its source, never read the token file or the agent's host to show it.
  • Don't write the Claude Code settings or a server declaration to configure the view agent: show the user the lines and where they go, and let them apply it.
  • Don't dump the full raw JSON to the user — render the table and the issue blocks. The raw JSON is for your own consumption.
  • Don't run write/delete tools as part of this skill. Read-only diagnostic.

When this skill fails

If list_vaults itself errors out (e.g., the router process crashed, MCP connection dead), report that distinctly:

⚠️ The Obsidian router MCP didn't respond. Possible causes:

  • The router binary obsidian-mcp-router isn't installed (run npm link in the repo)
  • ~/.claude.json doesn't have the router registered under mcpServers.obsidian-router (or whatever name)
  • Claude Desktop / Code wasn't restarted after the registration

Fix: verify with which obsidian-mcp-router and check the mcpServers block in ~/.claude.json.

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.