Skip to content
All Skills

Export Vault Note

Exports a single Obsidian vault note and all its linked images into a portable zip or tar.gz archive, preserving vault-root-relative paths so the archive unpacks correctly anywhere. Use only when the user explicitly invokes /export-vault-note.

Personal Productivity|v1|Updated 7/14/2026|GitHub source
MCP get_skill({ skillId: "export-vault-note-95fbafe9" })

Use this skill with your agent

Create a free account and connect via MCP

Get Started Free
# Export Vault Note

This skill runs inside an **Obsidian vault**. It bundles a single Markdown note and every image it links into a portable archive placed at a location of the user's choosing (defaulting to one directory above the vault root).

Handles two image link styles:
- Wiki-style: `![[image.png]]` or `![[subfolder/image.png]]`
- Inline Markdown: `![alt text](path/to/image.png)`

**Example:**
```
/export-vault-note projects/blog/my-post.md zip ~/Desktop
```

---

## Step 1 — Parse Arguments

Read `$ARGUMENTS`. Extract:
- `note_path` — vault-relative path to the Markdown file (e.g. `ai/notes/my-note.md`)
- `format` — `zip` or `tar`
- `output_dir` — absolute or relative path where the archive should be saved

If `note_path` is missing, ask: *"Which note do you want to export? Provide the vault-relative path, e.g. `ai/notes/my-note.md`."*

If `format` is not provided, ask: *"Do you want a `zip` or `tar` archive?"*

If `output_dir` is not provided, tell the user: *"The archive will be saved to one directory above the vault root by default. Is that OK, or do you want a different location?"* Wait for confirmation or a new path before continuing.

---

## Step 2 — Locate the Vault Root

Walk up the directory tree from the current working directory looking for a `.obsidian` folder. If the note path given is absolute, also try walking up from its parent directory.

```bash
python3 -c "
import sys
from pathlib import Path
for start in sys.argv[1:]:
    p = Path(start).resolve()
    for candidate in [p] + list(p.parents):
        if (candidate / '.obsidian').is_dir():
            print(candidate)
            raise SystemExit(0)
print('')
" "." "<absolute-note-parent-if-known>"
```

If the output is empty (no `.obsidian` found), ask: *"I couldn't detect the vault root automatically. What is the absolute path to your vault root?"*

---

## Step 3 — Run the Export

Write the script below to `/tmp/export_vault_note.py` and run it. The script is embedded directly so the skill works regardless of install location.

```bash
cat > /tmp/export_vault_note.py << 'PYEOF'
import sys
import re
import zipfile
import tarfile
from pathlib import Path


def find_vault_wide(vault_root, name):
    for p in vault_root.rglob(name):
        return p
    return None


def collect_images(vault_root, note_path):
    content = note_path.read_text(encoding="utf-8")
    note_dir = note_path.parent
    images = []
    warnings = []
    seen = set()

    wiki = re.findall(r"!\[\[([^\]|#]+)", content)
    inline = re.findall(r"!\[[^\]]*\]\(([^)#\s]+)", content)

    for ref in wiki + inline:
        ref = ref.strip()
        if not ref or ref in seen:
            continue
        seen.add(ref)

        if re.match(r"https?://", ref):
            warnings.append(f"Skipping external image: {ref}")
            continue

        abs_path = None
        if "/" in ref or "\\" in ref:
            for candidate in [vault_root / ref, note_dir / ref]:
                if candidate.exists():
                    abs_path = candidate
                    break
        else:
            found = find_vault_wide(vault_root, ref)
            if found:
                abs_path = found
                print(f"Resolved bare link '{ref}' -> {abs_path.relative_to(vault_root)}")

        if abs_path is None:
            warnings.append(f"Warning: image not found, skipping: {ref}")
            continue

        try:
            vault_rel = str(abs_path.relative_to(vault_root))
            images.append((abs_path, vault_rel))
        except ValueError:
            warnings.append(f"Warning: image outside vault, skipping: {abs_path}")

    return images, warnings


def main():
    if len(sys.argv) < 3:
        print(f"Usage: {sys.argv[0]} <vault_root> <note_rel_path> [zip|tar] [output_dir]", file=sys.stderr)
        sys.exit(1)

    vault_root = Path(sys.argv[1]).resolve()
    note_rel = sys.argv[2]
    fmt = sys.argv[3] if len(sys.argv) > 3 else "zip"
    output_dir = Path(sys.argv[4]).resolve() if len(sys.argv) > 4 else vault_root.parent

    if fmt not in ("zip", "tar"):
        print(f"Error: format must be 'zip' or 'tar', got '{fmt}'", file=sys.stderr)
        sys.exit(1)

    if not vault_root.is_dir():
        print(f"Error: vault root not found: {vault_root}", file=sys.stderr)
        sys.exit(1)

    note_path = vault_root / note_rel
    if not note_path.exists():
        print(f"Error: note not found: {note_path}", file=sys.stderr)
        sys.exit(1)

    if not output_dir.exists():
        output_dir.mkdir(parents=True)

    images, warnings = collect_images(vault_root, note_path)
    stem = note_path.stem

    if fmt == "tar":
        archive_path = output_dir / f"{stem}.tar.gz"
        with tarfile.open(archive_path, "w:gz") as tar:
            tar.add(note_path, arcname=note_rel)
            for abs_path, vault_rel in images:
                tar.add(abs_path, arcname=vault_rel)
    else:
        archive_path = output_dir / f"{stem}.zip"
        with zipfile.ZipFile(archive_path, "w", zipfile.ZIP_DEFLATED) as zf:
            zf.write(note_path, note_rel)
            for abs_path, vault_rel in images:
                zf.write(abs_path, vault_rel)

    print(f"Archive: {archive_path}")
    print(f"Note: {note_rel}")
    for _, vault_rel in images:
        print(f"Image: {vault_rel}")
    for w in warnings:
        print(w)


if __name__ == "__main__":
    main()
PYEOF
python3 /tmp/export_vault_note.py "<vault_root>" "<note_rel_path>" "<format>" "<output_dir>"
```

Substitute all four values. If the user accepted the default output location, resolve and pass `vault_root.parent` explicitly.

---

## Step 4 — Report Results

Parse the script output and report:

- **Archive created:** full path
- **Note inside archive:** vault-relative path
- **Images included:** one line each
- **Warnings:** skipped images, resolved bare links — display each prominently so the user can investigate if needed
#broad-capability#skill-authoring#code-review#documentation#obsidian#vault#managementpythonbash

Explore Other Categories

Skills from other categories with shared topics

Agentic Skeleton Dir Structure

Scaffolds production-ready directory structures for agentic AI projects using Agent-OS v3 (Builder Methods). Use when the user asks to set up, scaffold, initialize, or restructure a project for agentic development — including mono-repos, single repos, multi-language repos, full-stack, backend, frontend, or middleware projects. Triggers on "scaffold directory", "project structure", "agentic scaffold", "project layout", "initialize AI project", "directory structure", "agent-os setup", "mono-repo layout", "IaC structure".

Software Engineering#broad-capability#skill-authoring

Agent Os Profile Critique

Provides the audit checklists, severity criteria (blocking/warning/suggestion), and artifact patterns needed to properly review Agent OS profiles and standards. Always invoke this skill before auditing - without it you can only give generic feedback, not structured severity-tagged findings. Invoke when the user pastes a standard and asks if it is good or what is wrong with it; when the user asks to review, audit, validate, or critique an agent-os profile or standard; or when the user mentions "agent-os profile", "agent-os standard", or "my agent-os setup" in a review or validation context.

Software Engineering#broad-capability#skill-authoring

Arch Lens

Explores a codebase for architectural friction through the lens of Ousterhout's deep-module principle (small interface, large implementation). Seven-step interactive workflow: an Explore sub-agent navigates the codebase organically — the friction it experiences IS the signal. Surfaces candidate clusters with coupling reasons, call patterns, shared types, dependency categories, and existing tests that a boundary test would replace. User picks what to explore, frames the problem, then 3–4 parallel sub-agents design competing deep-module interfaces. Chosen design becomes a structured RFC action file readable by GitHub MCP or ROVO (Jira) MCP. Use when the user says "arch review", "find shallow modules", "module depth", "deep module", "Ousterhout", "testability audit", "surface coupling", "design interfaces", "RFC issues", or "architectural friction".

Software Engineering#broad-capability#skill-authoring