com um clique
obsidian
Link curator vault at <profile-dir>/vault/
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Menu
Link curator vault at <profile-dir>/vault/
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Baseado na classificação ocupacional SOC
| 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"] |
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).
<profile-dir>/vault/
### [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.
Use save_entry.py — atomic read+patch, never overwrites INDEX.md.
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:
--- separator--- separator (each entry gets its own chunk)vault/YYYY-MM-DD.md⚠️ Prepend bug (fixed): Old versions of
save_entry.pyinserted 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 usesre.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 changelines[:sep_idx]→lines[:sep_idx+1]so insertion happens AFTER the separator, not before. Runrebuild_index.pyto fix retroactively affected vaults.
Validate after save is automatic via the script. Manual validate (if needed):
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.
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:
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:
curl -s --max-time 8 "https://x.com/USER/status/ID" — if it returns HTML login page, X is blockingweb_search or save with [content unavailable]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.
# By content
grep -ri "keyword" <profile-dir>/vault/ --include="*.md"
# By date
ls <profile-dir>/vault/2026-05-*.md
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:
# 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.
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#local and #local-ai → always use #local-aiDo 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.
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:
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.
grep -c '^### ' <profile-dir>/vault/INDEX.md
# must equal sum of grep -c '^### ' vault/2026-05-*.md
If counts don't match: extract missing entries from INDEX and patch into the daily file.
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