Agent Skills: obsidian.nvim Skill

Guide for implementing obsidian.nvim - a Neovim plugin for Obsidian vault management. Use when configuring, troubleshooting, or extending obsidian.nvim features including workspace setup, daily notes, templates, completion, pickers, and UI customization.

UncategorizedID: julianobarbosa/claude-code-skills/obsidian-nvim

Install this agent skill to your local

pnpm dlx add-skill https://github.com/julianobarbosa/claude-code-skills/tree/HEAD/skills/obsidian-nvim

Skill Files

Browse the full folder contents for obsidian-nvim.

Download Skill

Loading file tree…

skills/obsidian-nvim/SKILL.md

Skill Metadata

Name
obsidian-nvim
Description
Guide for implementing obsidian.nvim - a Neovim plugin for Obsidian vault management. Use when configuring, troubleshooting, or extending obsidian.nvim features including workspace setup, daily notes, templates, completion, pickers, and UI customization.

obsidian.nvim Skill

A comprehensive guide for implementing and configuring obsidian.nvim - the Neovim plugin for managing Obsidian vaults.

Quick Start

Minimal Installation (lazy.nvim)

return {
  "obsidian-nvim/obsidian.nvim",
  version = "*",
  ft = "markdown",
  opts = {
    workspaces = {
      { name = "personal", path = "~/vaults/personal" },
    },
  },
}

System Requirements

  • Neovim: >= 0.10.0
  • ripgrep: Required for completion and search (brew install ripgrep)
  • pngpaste (macOS): For image pasting (brew install pngpaste)
  • xclip/wl-clipboard (Linux): For image pasting

Configuration

See references/configuration.md for complete configuration options.

Essential Configuration Options

require("obsidian").setup({
  -- Workspace configuration (required)
  workspaces = {
    { name = "personal", path = "~/vaults/personal" },
    { name = "work", path = "~/vaults/work" },
  },

  -- Daily notes
  daily_notes = {
    folder = "daily",
    date_format = "%Y-%m-%d",
    alias_format = "%B %-d, %Y",
    default_tags = { "daily-notes" },
  },

  -- Templates
  templates = {
    folder = "templates",
    date_format = "%Y-%m-%d",
    time_format = "%H:%M",
  },

  -- Note ID generation (Zettelkasten-style by default)
  note_id_func = function(title)
    local suffix = ""
    if title ~= nil then
      suffix = title:gsub(" ", "-"):gsub("[^A-Za-z0-9-]", ""):lower()
    else
      for _ = 1, 4 do
        suffix = suffix .. string.char(math.random(65, 90))
      end
    end
    return tostring(os.time()) .. "-" .. suffix
  end,

  -- Completion settings
  completion = {
    nvim_cmp = true,  -- or blink = true for blink.cmp
    min_chars = 2,
  },

  -- UI customization
  ui = {
    enable = true,
    checkboxes = {
      [" "] = { char = "󰄱", hl_group = "ObsidianTodo" },
      ["x"] = { char = "", hl_group = "ObsidianDone" },
    },
  },
})

Commands

See references/commands.md for complete command reference.

Primary Commands

| Command | Description | |---------|-------------| | :Obsidian | Open command picker | | :Obsidian today [OFFSET] | Open/create daily note | | :Obsidian new [TITLE] | Create new note | | :Obsidian search [QUERY] | Search vault with ripgrep | | :Obsidian quick_switch | Fuzzy find notes | | :Obsidian backlinks | Show references to current note | | :Obsidian template [NAME] | Insert template | | :Obsidian workspace [NAME] | Switch workspace |

Visual Mode Commands

| Command | Description | |---------|-------------| | :Obsidian link [QUERY] | Link selection to existing note | | :Obsidian link_new [TITLE] | Create note and link selection | | :Obsidian extract_note [TITLE] | Extract selection to new note |

Keymaps

Smart Action (Recommended: <CR>)

vim.keymap.set("n", "<CR>", function()
  if require("obsidian").util.cursor_on_markdown_link() then
    return "<cmd>Obsidian follow_link<CR>"
  else
    return "<CR>"
  end
end, { expr = true })

Navigation Links

vim.keymap.set("n", "[o", function()
  require("obsidian").util.nav_link("prev")
end, { buffer = true, desc = "Previous link" })

vim.keymap.set("n", "]o", function()
  require("obsidian").util.nav_link("next")
end, { buffer = true, desc = "Next link" })

Picker Integration

Configure your preferred picker:

picker = {
  name = "telescope",  -- or "fzf-lua", "mini.pick", "snacks.picker"
  note_mappings = {
    new = "<C-x>",
    insert_link = "<C-l>",
  },
  tag_mappings = {
    tag_note = "<C-x>",
    insert_tag = "<C-l>",
  },
},

Completion Integration

With blink.cmp

completion = {
  blink = true,
  nvim_cmp = false,
  min_chars = 2,
},

With nvim-cmp

completion = {
  nvim_cmp = true,
  blink = false,
  min_chars = 2,
},

Triggers:

  • [[ - Wiki link completion
  • [ - Markdown link completion
  • # - Tag completion

Templates

Template Variables

| Variable | Description | |----------|-------------| | {{title}} | Note title | | {{date}} | Current date | | {{time}} | Current time | | {{id}} | Note ID |

Custom Substitutions

templates = {
  folder = "templates",
  substitutions = {
    yesterday = function()
      return os.date("%Y-%m-%d", os.time() - 86400)
    end,
    tomorrow = function()
      return os.date("%Y-%m-%d", os.time() + 86400)
    end,
  },
},

Frontmatter Management

frontmatter = {
  enabled = true,
  func = function(note)
    local out = { id = note.id, aliases = note.aliases, tags = note.tags }
    if note.metadata ~= nil and not vim.tbl_isempty(note.metadata) then
      for k, v in pairs(note.metadata) do
        out[k] = v
      end
    end
    return out
  end,
  sort = { "id", "aliases", "tags" },
},

Troubleshooting

See references/troubleshooting.md for comprehensive troubleshooting.

Health Check

:checkhealth obsidian

Quick Fixes

| Issue | Solution | |-------|----------| | Completion not working | Install ripgrep: brew install ripgrep | | Picker not opening | Verify picker name matches installed plugin | | Images not pasting | macOS: brew install pngpaste | | Links not following | Ensure cursor is on [[link]] or [text](link) | | Checkboxes not rendering | Set :set conceallevel=2 | | Workspace not found | Verify path exists and file is inside vault |

Debug Mode

log_level = vim.log.levels.DEBUG,

Examples

See references/examples.md for practical configuration examples.

Resources


Gotchas

  • The plugin requires Obsidian to be running for live updates — vault changes from Neovim don't propagate to Obsidian's index until the app is open AND has focused the vault.
  • Completion source ordering conflicts with cmp-buffer — LSP completion may not show note suggestions if buffer source ranks higher; explicit sorting.priority_weight adjustment needed.
  • Daily-note template paths use Lua's os.date format, not Obsidian's natural-language date format — %Y-%m-%d in nvim, YYYY-MM-DD in Obsidian.
  • require("obsidian").get_client():resolve_link() returns nil for an unindexed file — even if the file exists. Force a :ObsidianRefresh after creating notes outside the plugin.
  • lazy.nvim lazy-loading on BufRead: the first vault file you open before plugin spec evaluation doesn't get note features — set lazy=false for obsidian.nvim or use a VeryLazy event.