A simple Neovim plugin for managing markdown notes and todos.
Note
The canonical repository is hosted on Codeberg, which contains the official issue tracker. GitHub is a read-write mirror: PRs are accepted on both and synchronized back to Codeberg.
- Create, delete, and list markdown notes
- No required dependencies — pure Lua + Vim API, no plenary
- Multi-picker support, auto-detected: snacks.nvim > telescope.nvim > fzf-lua >
vim.ui.select - Personal notes folder and project-local notes
- Works out-of-box with sensible defaults (no
setup()required)
- Neovim >= 0.10.0
- One of the pickers above (optional — falls back to
vim.ui.select)
Minimal (no picker dependency):
{ "lbartoletti/notes.nvim" }With snacks.nvim (recommended):
{
"lbartoletti/notes.nvim",
dependencies = { "folke/snacks.nvim" },
config = function()
require("notes").setup({
personal_notes_dir = vim.fn.expand("~/.notes"),
scope = "personal", -- "personal" | "project" | "auto"
})
end,
}With telescope (legacy):
{
"lbartoletti/notes.nvim",
dependencies = { "nvim-lua/plenary.nvim", "nvim-telescope/telescope.nvim" },
config = function()
require("notes").setup()
require("telescope").load_extension("notes")
end,
}:Note new [name] " Create a new note (prompts if no name given)
:Note delete [name] " Delete a note (with confirmation)
:Note list " List notes using vim.ui.select
:Note find " Open picker to browse notes by filename
:Note grep " Open picker to full-text search note contentlocal notes = require("notes")
notes.new_note("my-note")
notes.new_note("project-note", { scope = "project" })
notes.delete_note("/path/to/note.md")
local paths = notes.list_notes()
local dir = notes.get_notes_dir({ scope = "personal" })
require("notes.picker").notes() -- browse notes
require("notes.picker").grep() -- full-text search
require("notes.picker").notes({ scope = "project" })vim.keymap.set("n", "<leader>fn", function() require("notes.picker").notes() end, { desc = "Find notes" })
vim.keymap.set("n", "<leader>sn", function() require("notes.picker").grep() end, { desc = "Search notes" })
vim.keymap.set("n", "<leader>nn", function() require("notes").new_note() end, { desc = "New note" })
vim.keymap.set("n", "<leader>np", function() require("notes").new_note(nil, { scope = "project" }) end, { desc = "New project note" })require("notes").setup({
personal_notes_dir = vim.fn.stdpath("data") .. "/notes", -- ~/.local/share/nvim/notes
project_notes_dir = ".notes", -- relative to cwd
scope = "personal", -- "personal" | "project" | "auto"
file_extension = ".md",
confirm_delete = true,
picker = nil, -- nil = auto-detect, or "snacks"|"telescope"|"fzf-lua"|"builtin"
})personal(default): notes go topersonal_notes_dirproject: notes go toproject_notes_dir(relative to cwd)auto: project dir if inside a git repo, otherwise personal
Examples:
-- Personal knowledge base
require("notes").setup({ personal_notes_dir = vim.fn.expand("~/knowledge-base") })
-- Project notes with auto-switch
require("notes").setup({ scope = "auto" })Force a specific picker:
require("notes").setup({ picker = "telescope" })- No required dependencies — works on any system
- No timestamps — add in filename or frontmatter if needed
- No TODO states — markdown checkboxes are sufficient
- No syncing — use Git, Syncthing, etc.
- KISS — simple code, simple features
Contributions welcome. Keep the KISS principle: simplicity over features, no unnecessary dependencies.
MIT
- telekasten.nvim — full zettelkasten with links
- obsidian.nvim — Obsidian integration
- neorg — org-mode alternative
notes.nvim is simpler and lighter, focused purely on managing markdown files.