diff --git a/.claude/skills/vault/SKILL.md b/.claude/skills/vault/SKILL.md index 26fc033..5808063 100644 --- a/.claude/skills/vault/SKILL.md +++ b/.claude/skills/vault/SKILL.md @@ -1,112 +1,98 @@ --- name: vault -description: Read and write notes in ginnoir's self-hosted Obsidian vault (CouchDB obsidian-livesync backend at obsidian.ginnoir.com). Use when loading persistent context for a session, saving new context, writing a note, or querying vault contents. The vault is the canonical persistent-context store across Claude sessions. +description: Read and write notes in ginnoir's self-hosted Obsidian vault via the Obsidian MCP server. Use when loading persistent context for a session, saving new context, writing a note, or querying vault contents. The vault is the canonical persistent-context store across Claude sessions. --- # vault -Obsidian vault backed by CouchDB (obsidian-livesync) at `obsidian.ginnoir.com`. +Obsidian vault accessed via the **`mcp__obsidian__*` MCP tools**. Do not attempt to connect to CouchDB directly — use MCP only. -## Credentials +The MCP server is configured in `~/.mcp.json` and is available in every Claude Code session. If the tools are listed as deferred, load them with `ToolSearch` before calling. -``` -Endpoint : http://admin:couchdb_obs_p4ss_7x9k@localhost:5984 (via docker exec couchdb) -DB : obsidian -External : https://obsidian.ginnoir.com (also in stacks/notes/stack.env) -``` +## Core tools -## Document format (confirmed from live vault) - -obsidian-livesync uses a **two-level structure**: - -**File doc** — `_id` is the vault-relative path (e.g. `testing.md`, `claude/Context.md`): -```json -{ - "_id": "testing.md", - "path": "testing.md", - "type": "plain", - "children": ["h:1w5waerza6mc9"], - "ctime": 1780735543814, - "mtime": 1780735679684, - "size": 14, - "eden": {} -} -``` - -**Leaf/chunk doc** — `_id` is `h:`, holds the actual content: -```json -{ - "_id": "h:1w5waerza6mc9", - "data": "this is a test", - "type": "leaf" -} -``` - -Content lives in leaf docs. `children[]` lists chunk IDs in order (concatenate for large notes). -Slashes in paths must be URL-encoded as `%2F` in requests. - -## Read all notes (list) - -```powershell -ssh -o BatchMode=yes ginnoir@valhalla 'docker exec couchdb curl -sf "http://admin:couchdb_obs_p4ss_7x9k@localhost:5984/obsidian/_all_docs?include_docs=true"' -``` - -File docs: `type == "plain"`, `_id` does not start with `h:` or `obsydian_`. - -## Read one note's content - -```powershell -# 1. Get file doc — find chunk IDs in children[] -ssh -o BatchMode=yes ginnoir@valhalla 'docker exec couchdb curl -sf "http://admin:couchdb_obs_p4ss_7x9k@localhost:5984/obsidian/testing.md"' - -# 2. Fetch chunk — content is in .data -ssh -o BatchMode=yes ginnoir@valhalla 'docker exec couchdb curl -sf "http://admin:couchdb_obs_p4ss_7x9k@localhost:5984/obsidian/h%3A1w5waerza6mc9"' -``` - -## Write a new note - -Write the leaf first, then the file doc. Use a fixed chunk ID so you can update it later. - -```bash -ssh -o BatchMode=yes ginnoir@valhalla ' - B="http://admin:couchdb_obs_p4ss_7x9k@localhost:5984" - NOW=$(date +%s%3N) - CHUNK="h:claude_ctx_1" - CONTENT="# My Note\n\nContent here." - - docker exec couchdb curl -sf -X PUT "$B/obsidian/$CHUNK" \ - -H "Content-Type: application/json" \ - -d "{\"data\":\"$CONTENT\",\"type\":\"leaf\"}" - - docker exec couchdb curl -sf -X PUT "$B/obsidian/claude%2FContext.md" \ - -H "Content-Type: application/json" \ - -d "{\"path\":\"claude/Context.md\",\"type\":\"plain\",\"children\":[\"$CHUNK\"],\"ctime\":$NOW,\"mtime\":$NOW,\"size\":${#CONTENT},\"eden\":{}}" -' -``` - -## Update an existing note - -Fetch `_rev` for both the file doc and chunk doc, then re-PUT both with `_rev` included. - -For complex content (markdown with quotes/newlines), write JSON to `/tmp/` on valhalla, `docker cp` into container, and `curl -d @/tmp/file.json` — avoids shell escaping. +| Tool | Use | +|---|---| +| `mcp__obsidian__vault_list` | List files/dirs in a directory (omit path for vault root) | +| `mcp__obsidian__vault_read` | Read a file's full content + metadata (tags, frontmatter, links, backlinks) | +| `mcp__obsidian__vault_write` | Create or overwrite a file | +| `mcp__obsidian__vault_patch` | Append or patch a section without a full rewrite | +| `mcp__obsidian__vault_delete` | Delete a file | +| `mcp__obsidian__vault_move` | Move or rename a file | +| `mcp__obsidian__search_simple` | Full-text search across the vault | +| `mcp__obsidian__search_query` | Advanced query search | +| `mcp__obsidian__tag_list` | List all tags | ## Load context at session start -```powershell -# Get all file docs and their chunk content -ssh -o BatchMode=yes ginnoir@valhalla 'docker exec couchdb curl -sf "http://admin:couchdb_obs_p4ss_7x9k@localhost:5984/obsidian/_all_docs?include_docs=true"' | python -c " -import sys, json -d = json.load(sys.stdin) -chunks = {r['id']: r['doc']['data'] for r in d['rows'] if r['id'].startswith('h:')} -for r in d['rows']: - doc = r['doc'] - if doc.get('type') == 'plain' and not doc.get('deleted'): - content = ''.join(chunks.get(c, '') for c in doc.get('children', [])) - print(f'=== {doc[\"_id\"]} ===') - print(content) -" +``` +1. mcp__obsidian__vault_read path="claude/Context.md" +2. Follow [[wikilinks]] to read specific notes as needed ``` -## Notes on valhalla Python +`claude/Context.md` is the master index. It links to all other context notes under `claude/`. -`python3` on the valhalla *host* cannot resolve `localhost` (DNS issue in SSH env). Always use `docker exec couchdb curl` — the container resolves localhost fine. On the Windows Claude Code host, use `python` (not `python3`). +## Read a note + +``` +mcp__obsidian__vault_read path="claude/Homelab.md" +``` + +Returns: `content` (full markdown), `tags`, `frontmatter`, `links`, `backlinks`, `stat`. + +To read only a section: +``` +mcp__obsidian__vault_read path="claude/Services.md" targetType="heading" target="BookStack" +``` + +## Write a note + +``` +mcp__obsidian__vault_write path="claude/MyNote.md" content="# Title\n\nContent here." +``` + +Creates parent directories automatically. Overwrites without warning. + +## Append to a note + +``` +mcp__obsidian__vault_patch path="claude/Context.md" ... +``` + +Use `vault_patch` when adding a section to an existing note to avoid rewriting the whole file. + +## Search the vault + +``` +mcp__obsidian__search_simple query="portainer env vars" +``` + +## Vault structure + +``` +claude/ + Context.md — master index, session start guide, quick nav + Homelab.md — topology, stacks, networks, paths + Deploy.md — deployment channels + SSH.md — SSH ops, container management + Portainer.md — env interpolation gotcha, new stack registration + Services.md — per-service quirks (BookStack, Caddy, secrets policy) + ROM Library.md — RomM, igir, Pokémon romhacks, EmuDeck tree + Monitoring.md — Uptime Kuma v2 socket technique + Vault.md — this stack's infrastructure, MCP access +testing.md — original connectivity test note +Pokémon ROM Hacks/ + _Claude.md — ROM hack vault ops: schema, update patterns, new-hack checklist + Index.md — all 75 hacks directory (Dataview + static) + Play Queue.md — play tracking dashboard + Hacks/ — 75 notes, one per hack + Bases/ — per-base MOCs (FireRed / Emerald / Crystal / Ruby / NDS) + Platforms/ — per-system MOCs (GBA / GBC / GB / NDS) +``` + +## Load tool schemas (if deferred) + +If `mcp__obsidian__vault_read` is not yet callable, run: +``` +ToolSearch query="select:mcp__obsidian__vault_list,mcp__obsidian__vault_read,mcp__obsidian__vault_write" +```