Agent skill

Link Curator Obsidian Vault

by dodo-reach in dodo-reach/hermes-link-curator

Archives links a user sends into a profile's Obsidian-style vault with a save script and replies with a one-word confirmation instead of a summary.

MITAuto-check passedKnowledge Management

Install Link Curator Obsidian Vault

skills CLI
$ npx skills add dodo-reach/hermes-link-curator --skill obsidian -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install dodo-reach/hermes-link-curator obsidian --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/dodo-reach/hermes-link-curator.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skill-obsidian .claude/skills/obsidian && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
obsidian
GitHub stars
142
Token cost
~2.8k tokens
SKILL.md length
768 words
Files
3 (incl. scripts)
Skills in repo
2
Repo updated
First seen
Licence
MIT

At a glance

Archives links a user sends into a profile's Obsidian-style vault with a save script and replies with a one-word confirmation instead of a summary.

  • Works in 5 steps: Reads INDEX.md in memory (never… → Finds the first --- separator → Inserts the new entry AFTER the first… → …
  • Saving links to a curated vault without writing summaries
  • SKILL.md covers Behavior — do not summarize,…, Vault, Entry format and Save workflow, plus 8 more sections
  • Runs Python scripts from its folder; calls python3, curl and vault; reaches x.com

What it does

The agent acts as a librarian: when you send a URL or ask to save something, it files the entry immediately, does not summarize it unless asked, and answers only with a short confirmation or the error. Entries have a title, the URL and a type such as github, x-post, article, tool, video, paper or other, with a separator line between entries so the dashboard can split them.

Saving goes through `save_entry.py`, which reads the index first, inserts the new entry after the first separator, appends to a daily note named by date, and runs `validate.py`. A note describes an earlier bug that merged same-day entries in one chunk and explains how `rebuild_index.py` repairs affected vaults. For X posts that hit login walls, an optional local browser-session service can fetch the content. The excerpt is cut off in that section.

When your agent uses it

  • Saving links to a curated vault without writing summaries
  • Fixing an index where saved entries do not show up in the dashboard
  • Fetching an X post that normal page extraction cannot read

Example prompts

  • “Save https://github.com/example/project as a tool entry in the vault.”
  • “Archive this article link and add it to today's daily note.”
  • “Some entries are in INDEX.md but missing from the dashboard, rebuild the index.”

Requirements

  • Python 3 to run the save, validate and rebuild scripts
  • A profile folder containing the vault and dashboard

Workflow steps

5 steps, taken from the first numbered list in SKILL.md.

  1. Reads INDEX.md in memory (never overwrites without reading)
  2. Finds the first --- separator
  3. Inserts the new entry AFTER the first --- separator (each entry gets its own chunk)
  4. Also appends to the daily note vault/YYYY-MM-DD.md
  5. Runs validate.py automatically

What it can do on your machine

Read from SKILL.md and the folder at commit 5bd4d5a. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Ships 2 files in scripts/ (Python), which the agent can run.

    Shell commands in SKILL.md call:

    • python3
    • curl
    • vault

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Hosts in commands or code, which the agent is likely to contact:

    • x.com

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Link Curator Obsidian Vault loads about 2.8k tokens when it runs. Until then it costs about 13 tokens; SKILL.md has 768 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~13
When it runs · the whole SKILL.md, loaded when a task matches
~2.8k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); the scripts in this folder are not scanned.

SKILL.md

The full file from dodo-reach/hermes-link-curator at commit 5bd4d5a, republished under its MIT licence (© dodo-reach). 768 words, ~2,796 tokens.

Download SKILL.mdSave it as .claude/skills/obsidian/SKILL.md (or your agent's skills folder). This skill also uses 2 other files; get the full folder from GitHub.
name
obsidian
description
Link curator vault at <profile-dir>/vault/
triggers
save link, archive URL, add to vault, link curator, user sends an URL/link, user says save/archive/add to vault

Behavior — do not summarize, archive

When the user sends a URL or asks to save/archive something: archive it immediately, do not summarize. Your job is that of a librarian: receive → process → file. Not a chatbot to give impressions.

Do NOT respond with a summary of the content unless the user explicitly asks for one. Archive first, then say only "Salvato." (or the error, if any).

Vault

<profile-dir>/vault/

Entry format

### [Title]
- **URL**: https://...
- **Type**: `github` | `x-post` | `article` | `tool` | `video` | `paper` | `other`
- **Tags**: #tag1 #tag2 #tag3
- **Added**: YYYY-MM-DD
- **Summary**: What is this? Why does it matter? What do you do with it?

---

[next entry]

--- between every entry. No --- = merged entry in dashboard. Parse splits on \n---\n.

Save workflow

Use save_entry.py — atomic read+patch, never overwrites INDEX.md.

bash
python3 <profile-dir>/skills/note-taking/obsidian/scripts/save_entry.py \
  --url "https://..." \
  --title "Entry Title" \
  --type "article" \
  --tags "ai dev-tools" \
  --added "2026-06-04" \
  --summary "What it is and why it matters."

The script:

  1. Reads INDEX.md in memory (never overwrites without reading)
  2. Finds the first --- separator
  3. Inserts the new entry AFTER the first --- separator (each entry gets its own chunk)
  4. Also appends to the daily note vault/YYYY-MM-DD.md
  5. Runs validate.py automatically

⚠️ Prepend bug (fixed): Old versions of save_entry.py inserted new entries BETWEEN the header and the first ---. When two entries from the same day were saved consecutively, they ended up in the same chunk. The dashboard parser uses re.findall(r'\*\*URL\*\*', chunk)[0] — only the first URL per chunk was read. Symptoms: entry appears in INDEX.md but not in dashboard (or dashboard shows fewer entries than vault count). Fix was to change lines[:sep_idx] → lines[:sep_idx+1] so insertion happens AFTER the separator, not before. Run rebuild_index.py to fix retroactively affected vaults.

Validate after save is automatic via the script. Manual validate (if needed):

bash
cd <profile-dir>/dashboard && python3 validate.py

Manual workflow (only if script unavailable): fetch → append to daily → read INDEX first, then patch to prepend. Never use write_file on INDEX.md.

X/Twitter — optional browser-session fetch

web_extract and browser_navigate may return login walls on X. If camofox is installed and the content is important, use its local REST API:

bash
CAMOFOX_USER_ID="${CAMOFOX_USER_ID:-link-curator}"
TAB=$(curl -s -X POST http://localhost:9377/tabs \
  -H "Content-Type: application/json" \
  -d "{\"userId\":\"$CAMOFOX_USER_ID\",\"sessionKey\":\"link-curator\",\"url\":\"https://x.com/USERNAME/status/POST_ID\"}")
TAB_ID=$(echo "$TAB" | python3 -c "import sys,json; print(json.load(sys.stdin)['tabId'])")
sleep 3
curl -s "http://localhost:9377/tabs/$TAB_ID/snapshot?userId=$CAMOFOX_USER_ID" > /tmp/snap.json
python3 -c "import sys,json; d=json.load(open('/tmp/snap.json')); print(d.get('snapshot','')[:6000])"
curl -s -X DELETE "http://localhost:9377/tabs/$TAB_ID?userId=$CAMOFOX_USER_ID"

Content is in .snapshot, NOT .accessibilityTree.content. jq is not available — always use python3 for JSON parsing.

If camofox fails: web_search fallback, then save URL + [content unavailable] in Summary.

Quick probe before long fetch — when the URL is an X post and you need content for the Summary:

  1. curl -s --max-time 8 "https://x.com/USER/status/ID" — if it returns HTML login page, X is blocking
  2. If blocked → skip camofox, go straight to web_search or save with [content unavailable]
  3. Only use camofox (tab + sleep + snapshot) when you have reason to believe it will succeed and the content is high-value

User-provided context shortcut

When the user says "this link is about X" or provides the summary framing directly, trust it and stop digging. Do not spend extra tool calls trying to extract more context from the page — the user already told you what matters. Supplement with whatever minimal snapshot data is readily available, then save. Examples:

  • "é un video che spiega che codex può lanciare, pinnare e gestire worktrees" → use that framing, add minimal post metadata (author, engagement) from snapshot, done.
  • "save this, it's about local LLMs" → accept the user's framing, don't try to fetch deeper content.

Only fall back to [content unavailable] if camofox itself fails AND no user context was provided.

Show full SKILL.md (274 more words)Show less

Search vault

bash
# By content
grep -ri "keyword" <profile-dir>/vault/ --include="*.md"

# By date
ls <profile-dir>/vault/2026-05-*.md

validate.py path

The validate script lives in the dashboard directory, NOT in the profile vault. In a standard install the dashboard is at ~/.hermes/profiles/<profile>/dashboard/ and the vault is at ~/.hermes/profiles/<profile>/vault/.

Always check the actual path before running:

bash
# Find validate.py
find ~ -name "validate.py" 2>/dev/null | grep -i dashboard

Never hardcode a path you haven't verified. The cd must target the dashboard directory, not the vault.

Tag normalization conventions

Keep tags consistent across the vault. When saving new entries, follow these rules:

  • #open-source — never use #open alone
  • #dev-tools — for developer tooling entries (CLI, agents, utility scripts). Use #dev-tools consistently, not #tooling or #tools (except for entries that are genuinely about design/general tools)
  • #local-ai — for local inference, Apple Silicon, on-device ML
  • Merge #local and #local-ai → always use #local-ai

Status field

Do NOT use **Status**: 'unread' or any other status markers. The vault stores processed entries only. For items to revisit later, use a bookmarking tool outside the vault (read-later app, pin board, etc.).


## Dashboard (port 8090) — separate process

The link-curator dashboard runs at `http://localhost:8090`. It is a standalone FastAPI app, not part of the official Hermes dashboard (`hermes dashboard`, default port 9119). The two are independent and can run side-by-side. See the `link-curator-dashboard` skill for full maintenance and restart procedures.

## Architecture rules (critical — never violate)

**Entry blocks do NOT contain `---`. The separator is added at write time.**

`build_entry_block()` returns text ending in `\n` (no `---`). Both `append_to_daily()` and `prepend_to_index()` add `\n---\n` or `\n---` as a separator when writing. If you put `---` inside `build_entry_block`, you get double `---` on prepend, which corrupts the dashboard parse.

**Never use `write_file` on INDEX.md.** The only safe operations are `read_file` first, then `patch`. Even for "quick edits" — read first, patch, never overwrite. The script enforces this; manual workflow must follow it too.

**INDEX.md headers differ by profile.** The `prepend_to_index` function finds the first `---` separator regardless of what header text precedes it:
- Default: `# Index` followed by `---`
- Custom profile headers are also fine as long as the first separator is `---`

Do NOT look for a specific header string — find the first `---` and insert after it.

**Validate after every save.** Run `validate.py` from the dashboard directory, not the vault.

## validate.py — common fixes

**Empty entry error ("Missing or malformed ### title line")**:  
Usually caused by a double `---` separator creating an empty chunk. Fix: remove the duplicate `---` between two consecutive entries in INDEX.md, leaving only one.

**Title uses em-dash (—) instead of hyphen-minus (-)**:
The parser accepts both in titles, but the `validate.py` script warns on em-dashes. More importantly, some edge cases in the title regex (`^###\s+[^\n—]+?\s+—\s+`) can fail to parse a title that has an em-dash mid-string. **Always use hyphen-minus (`-`) as the title separator in vault entries.** Example: `### Claude Code + Screen Recording Workflow - UI Bug Fixing` not `—`.

**Title validation fails for `# Index` header**:  
The title check `r'^###\s+\S'` rejects `# Heading` (single `#`). Chunk 5 (`# Index`) was a valid non-entry header — the URL filter already correctly skips non-entry blocks. Working title regex: `r'^#{1,3}\s+\S'` accepts h1–h3. The URL filter is the primary guard; the title regex is secondary.

---

## INDEX.md Health Check — when to run + manual verification

Run `validate.py` and do a manual chunk split when:
- Entries saved via `save_entry.py` appear in INDEX.md but not in the dashboard
- Dashboard shows fewer entries than vault count suggests
- You made manual edits to INDEX.md (patch, rebuild, etc.)

### validate.py output thresholds

| Result | Meaning |
|--------|---------|
| `Has errors: 0` | Vault is parse-safe. Dashboard will show all entries. |
| `Has errors: >0` | Structural corruption — entries may be missing from dashboard |
| `Fully valid: N` | Entries that pass all field checks |
| `Has warnings: M` | Non-fatal (em-dashes in titles, missing optional fields) — dashboard still works |

**Always run validate.py after any INDEX.md edit.** It's the only way to catch double-`---` chunks and merged entries before the user sees wrong counts.

### Manual chunk analysis (Python one-liner for ad-hoc checks)

```python
content = open('<profile-dir>/vault/INDEX.md').read()
chunks = content.split('\n---\n')
for i, chunk in enumerate(chunks):
    titles = [l for l in chunk.split('\n') if l.strip().startswith('###')]
    if len(titles) > 1:
        print(f"⚠️  Chunk {i}: MERGED {len(titles)} entries")
    if '\n---\n' in chunk:
        print(f"⚠️  Chunk {i}: double separator")
print(f"✅ {len(chunks)} chunks total, {sum(1 for c in chunks if '**URL**' in c)} with URLs")

This catches the prepend bug (two entries in same chunk) and orphaned --- separators (empty chunks) faster than re-reading by eye.


DISASTER RECOVERY

INDEX.md missing or overwritten

Root cause: write_file on INDEX.md without reading first wipes all entries. If only recent dates appear in dashboard (e.g. June only, May gone), INDEX.md was overwritten.

Fix — run the rebuild script:

bash
cd <profile-dir>/skills/note-taking/obsidian/scripts
python3 rebuild_index.py

Prevention: ALWAYS use save_entry.py for new saves. Never write_file directly on INDEX.md.

bash
grep -c '^### ' <profile-dir>/vault/INDEX.md
# must equal sum of grep -c '^### ' vault/2026-05-*.md
Reconciliation (INDEX vs daily notes out of sync)

If counts don't match: extract missing entries from INDEX and patch into the daily file.

Common failure mode

write_file on INDEX.md without reading first = overwrite destroys all entries. Always read_file first, then patch.

  • camofox — for browser-session fetching on sites that block simple extraction

© dodo-reach, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 2 other files (scripts) in skill-obsidian of dodo-reach/hermes-link-curator.

  • SKILL.md
  • scripts/rebuild_index.py
  • scripts/save_entry.py

Open the folder on GitHubat commit 5bd4d5a

Compare with similar skills

Link Curator Obsidian Vault next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Link Curator Obsidian Vault compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Link Curator Obsidian Vault this skilldodo-reach/hermes-link-curator142—~2.8kAutomated safety check: PassMIT
LLM Wikilewislulu/llm-wiki-skill655—~3.7kAutomated safety check: PassNone
Obsidian CLIpablo-mano/Obsidian-CLI-skill450—~3.2kAutomated safety check: PassNone
Obsidian Project Knowledge BaseGalaxy-Dawn/claude-scholar5.7k—~551Automated safety check: PassMIT
LLM WikiCharlesHoskinson/sevenlayer116—~1.5kAutomated safety check: PassCustom licence
Save to Obsidian VaultAgriciDaniel/claude-obsidian15k—~1.3kAutomated safety check: PassMIT

Similar skills

  • LLM Wiki

    lewislulu/llm-wiki-skill

    Build and maintain a Karpathy-style LLM knowledge base — a self-compiling Obsidian markdown wiki where an Agent ingests raw sources, compiles cross-linked concept/entity/summary pages, answers…

    655 GitHub stars~3.7k tokensUpdated 5 mo ago
    Knowledge ManagementAuto-check passed
  • Obsidian CLI

    pablo-mano/Obsidian-CLI-skill

    Lets the agent read, write, search and tidy an Obsidian vault directly through the official Obsidian command-line interface.

    450 GitHub stars~3.2k tokensUpdated 7 mo ago
    Knowledge ManagementAuto-check passed
  • Obsidian Project Knowledge Base

    Galaxy-Dawn/claude-scholar

    Maintains a project-scoped Obsidian research knowledge base: bootstrapping its folders, routing notes, updating hub, plan and index notes, and linting.

    5.7k GitHub stars~551 tokensUpdated 16 days ago
    Knowledge ManagementAuto-check passed
  • LLM Wiki

    CharlesHoskinson/sevenlayer

    Builds and maintains a persistent, interlinked Obsidian-compatible markdown knowledge wiki in a git repo via three operations — ingest a source into linked pages, answer a question from the…

    116 GitHub stars~1.5k tokensUpdated 1 mo ago
    Knowledge ManagementAuto-check passed
  • Save to Obsidian Vault

    AgriciDaniel/claude-obsidian

    Files a specific answer, decision or insight you point to in a conversation as one reviewed note in your Obsidian vault, and only when you ask for it.

    15k GitHub stars~1.3k tokensUpdated 28 days ago
    Knowledge ManagementAuto-check passed
  • Ray Obsidian Vault Setup

    imraywang/rayskills

    Sets up, audits or incrementally upgrades a local Obsidian vault for knowledge work and content production, without overwriting or moving existing notes.

    159 GitHub stars~625 tokensUpdated 16 days ago
    Knowledge ManagementAuto-check passed

More from dodo-reach/hermes-link-curator

  • Link Curator Dashboard Maintainer

    dodo-reach/hermes-link-curator

    Maintains and debugs the FastAPI-based link-curator web dashboard on port 8090, a separate process from the official Hermes dashboard.

    142 GitHub stars~2.6k tokensUpdated 4 mo ago
    Auto-check passed

Works with

Questions about Link Curator Obsidian Vault

What does Link Curator Obsidian Vault do?

Archives links a user sends into a profile's Obsidian-style vault with a save script and replies with a one-word confirmation instead of a summary. The agent acts as a librarian: when you send a URL or ask to save something, it files the entry immediately, does not summarize it unless asked, and answers only with a short confirmation or the error. Entries have a title, the URL and a type such as github, x-post, article, tool, video, paper or other, with a separator line between entries so the dashboard can split them.

When should I use Link Curator Obsidian Vault?

Link Curator Obsidian Vault fits situations like: saving links to a curated vault without writing summaries; fixing an index where saved entries do not show up in the dashboard; fetching an X post that normal page extraction cannot read.

How do I install Link Curator Obsidian Vault in Claude Code?

Run `npx skills add dodo-reach/hermes-link-curator --skill obsidian -a claude-code`. Or copy the skill folder (skill-obsidian in dodo-reach/hermes-link-curator) into .claude/skills/obsidian in your project. Claude Code loads it when a task matches its description.

How do I install Link Curator Obsidian Vault in Codex?

Run `npx skills add dodo-reach/hermes-link-curator --skill obsidian -a codex`. Or copy the skill folder (skill-obsidian in dodo-reach/hermes-link-curator) into .agents/skills/obsidian in your project. Codex loads it when a task matches its description.

Can I use Link Curator Obsidian Vault in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add dodo-reach/hermes-link-curator --skill obsidian -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/obsidian, .gemini/skills/obsidian, .github/skills/obsidian and .opencode/skills/obsidian in your project.

What does Link Curator Obsidian Vault need to run?

Going by SKILL.md and its folder, Link Curator Obsidian Vault needs Python for the scripts in its folder and the command-line tools its instructions call (python3, curl and vault). Our summary lists: Python 3 to run the save, validate and rebuild scripts; A profile folder containing the vault and dashboard.

Does Link Curator Obsidian Vault access the network?

SKILL.md names 1 domain. In commands or code: x.com; the agent is likely to contact it when it follows the instructions. This is read from the text; nothing was executed.

Is Link Curator Obsidian Vault safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. The check reads SKILL.md only: the scripts in the folder are not scanned, so read them before running anything.

What licence does Link Curator Obsidian Vault use?

Link Curator Obsidian Vault is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Link Curator Obsidian Vault use?

About 2.8k tokens (SKILL.md is roughly 11k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Link Curator Obsidian Vault?

Skills that share tags, products or a category with Link Curator Obsidian Vault: LLM Wiki (lewislulu/llm-wiki-skill, 655 stars), Obsidian CLI (pablo-mano/Obsidian-CLI-skill, 450 stars), Obsidian Project Knowledge Base (Galaxy-Dawn/claude-scholar, 5.7k stars) and LLM Wiki (CharlesHoskinson/sevenlayer, 116 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Link Curator Obsidian Vault?

dodo-reach (a GitHub user) maintains it in dodo-reach/hermes-link-curator, which has 142 GitHub stars. The repository holds 2 skills in this directory. The repository was last updated on June 6, 2026.

Source: dodo-reach/hermes-link-curator on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.