AgentStack
SKILL verified MIT Self-run

Obsidian

skill-furkangonel-cowrangler-obsidian · by furkangonel

Obsidian vault management — create notes, backlinks, tags, and Dataview queries via file operations

No reviews yet
0 installs
5 views
0.0% view→install

Install

$ agentstack add skill-furkangonel-cowrangler-obsidian

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access Used
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution Used

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Obsidian? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Obsidian Vault Management

Goal

Create, update, and organize notes in an Obsidian vault programmatically. Query notes with Dataview syntax. Maintain a consistent vault structure.

Vault Structure

vault/
├── Daily Notes/          # YYYY-MM-DD.md
├── Projects/             # One folder per project
├── Areas/                # Ongoing responsibilities
├── Resources/            # Reference material
├── Archive/              # Inactive notes
└── _templates/           # Note templates

Use PARA method (Projects / Areas / Resources / Archive) as the default organization.

Frontmatter Conventions

Every note should have frontmatter:

---
title: Note Title
date: 2024-01-15
tags: [topic, subtopic]
aliases: [alternative-name]
status: draft | active | archived
related: [[Other Note]], [[Another Note]]
---
  • date: ISO 8601 (YYYY-MM-DD)
  • tags: lowercase, hyphenated
  • aliases: alternate names for search/linking
  • status: lifecycle state
  • related: explicit links (supplement to inline wikilinks)

Creating Notes Programmatically

Basic note creation

from pathlib import Path
from datetime import datetime

def create_note(vault_path: str, folder: str, title: str, content: str, tags: list[str] = []) -> Path:
    vault = Path(vault_path)
    target_dir = vault / folder
    target_dir.mkdir(parents=True, exist_ok=True)
    
    # Sanitize title for filename
    filename = title.replace("/", "-").replace(":", "-") + ".md"
    note_path = target_dir / filename
    
    frontmatter = f"""---
title: {title}
date: {datetime.now().strftime("%Y-%m-%d")}
tags: {tags}
---

"""
    note_path.write_text(frontmatter + content, encoding="utf-8")
    return note_path

Daily note

def create_daily_note(vault_path: str, template: str = "") -> Path:
    today = datetime.now().strftime("%Y-%m-%d")
    content = template or f"""# {today}

## Tasks
- [ ] 

## Notes

## Links
"""
    return create_note(vault_path, "Daily Notes", today, content)

Wikilink Syntax

[[Note Title]]                    # Basic link
[[Note Title|Display Text]]       # Link with alias
[[Note Title#Heading]]            # Link to section
![[Note Title]]                   # Embed note
![[image.png]]                    # Embed image

Adding backlinks programmatically

def add_backlink(note_path: str, linked_title: str):
    path = Path(note_path)
    content = path.read_text(encoding="utf-8")
    link = f"[[{linked_title}]]"
    if link not in content:
        content += f"\n\n## Related\n{link}\n"
        path.write_text(content, encoding="utf-8")

Tag Management

import re

def add_tags(note_path: str, new_tags: list[str]):
    path = Path(note_path)
    content = path.read_text(encoding="utf-8")
    
    # Find existing tags in frontmatter
    match = re.search(r'^tags:\s*\[([^\]]*)\]', content, re.MULTILINE)
    if match:
        existing = [t.strip() for t in match.group(1).split(",") if t.strip()]
        merged = list(set(existing + new_tags))
        content = content[:match.start()] + f"tags: {merged}" + content[match.end():]
        path.write_text(content, encoding="utf-8")

def find_notes_by_tag(vault_path: str, tag: str) -> list[Path]:
    vault = Path(vault_path)
    results = []
    for md in vault.rglob("*.md"):
        if f"#{tag}" in md.read_text() or f'"{tag}"' in md.read_text():
            results.append(md)
    return results

Dataview Queries

Dataview plugin queries (placed inside dataview code blocks in notes):

List notes by tag

````markdown

LIST
FROM #project
SORT date DESC

````

Table of tasks

````markdown

TABLE date, status, tags
FROM "Projects"
WHERE status != "archived"
SORT date DESC

````

Incomplete tasks across vault

````markdown

TASK
WHERE !completed
FROM "Projects"
GROUP BY file.link

````

Notes modified this week

````markdown

LIST
WHERE file.mtime >= date(today) - dur(7 days)
SORT file.mtime DESC

````

Search and Query (CLI)

# Find all notes containing a phrase
grep -rl "search term" /path/to/vault --include="*.md"

# Find broken wikilinks (links with no matching file)
python3 5000 notes; use search instead

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [furkangonel](https://github.com/furkangonel)
- **Source:** [furkangonel/cowrangler](https://github.com/furkangonel/cowrangler)
- **License:** MIT
- **Homepage:** https://cowrangler.com

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.