Dotmd.nvim
๐ Organize. Navigate. Create. Markdown. Keep all your notes, todos, and journals inside Neovim without ever leaving the editor.
Install / Use
/learn @y3owk1n/Dotmd.nvimREADME
๐ dotmd.nvim
Organize. Navigate. Create. Markdown. Keep all your notes, todos, and journals inside Neovim without ever leaving the editor.
<!-- panvimdoc-ignore-start -->https://github.com/user-attachments/assets/509f19d9-4172-4708-ad48-6a31735e6a6b
๐ค Why dotmd.nvim?
"I just want to write Markdown files... fast."
As a Neovim user, we spent most of our time in the editor. Yet everytime when we need to:
- Jot a quick thought
- Write a note
- Create a daily journal
- Track todos
...we end up reaching for external underused but overpowered apps or fighting complex plugins.
dotmd.nvim fixes this with:
- โก Zero context-switching - Manage everything in Neovim
- ๐ฏ Dead-simple workflow - No databases, no proprietary formats, just Markdown that we loved
- ๐ Batteries included - Smart templates, navigation, and cross-device sync ready (It's just Markdown files and folders)
โจ Features
- ๐ Zero Context-Switching: Stay in Neovim.
- ๐ Effortless Organization: Auto-created directories for notes, todos, journals, plus an inbox file.
- ๐ฉ Smart File Creation: Use adaptive templates.
- โช Todo Time Machine: Automatically roll over unfinished tasks.
- ๐งญ Rapid Navigation: Jump between entries with ease.
- ๐ Universal Search: Fuzzy-match files with Telescope, fzf-lua, snacks.nvim, or mini.pick.
- โ๏ธ Complete Customizability: Tweak directories, templates, split directions, and more.
๐ Contents
<!-- panvimdoc-ignore-end -->๐ฆ Installation
Using lazy.nvim:
-- dotmd.lua
return {
"y3owk1n/dotmd.nvim",
version = "*", -- remove this if you want to use the `main` branch
opts = {
-- your configuration comes here
-- or leave it empty to use the default settings
-- refer to the configuration section below
}
}
If you are using other package managers you need to call setup:
require("dotmd").setup({
-- your configuration
})
Requirements
- Neovim 0.9+ with Lua support
- The following CLI tools must be available in your $PATH:
find: for listing files across note directoriesgrep: for searching files across note directories
- (Optional but recommended) One of the following picker for better picking files and grepping:
โ๏ธ Configuration
[!important] Make sure to run
:checkhealth dotmdif something isn't working properly.
dotmd.nvim is highly configurable. And the default configurations are as below.
Default Options
---@alias DotMd.Split "vertical" | "horizontal" | "float" | "none" Split direction
---@alias DotMd.PickerType "telescope" | "fzf" | "snacks" | "mini" Picker type
---@class DotMd.Config
---@field root_dir? string Root directory of dotmd, default is `~/dotmd`
---@field default_split? DotMd.Split Split direction for new or existing files, default is `none`
---@field picker? DotMd.PickerType Picker type, default is `nil`
---@field rollover_todo? DotMd.Config.RolloverTodo
---@field dir_names? DotMd.Config.DirNames
---@field templates? Dotmd.Config.Templates
---@class DotMd.Config.RolloverTodo
---@field enabled? boolean Rollover the nearest previous unchecked todos to today's date, default is `false`
---@field headings? string[] H2 Headings to search for in your todos template to rollover, default is { "Tasks" }
---@class DotMd.Config.DirNames
---@field notes? string Directory name for notes, default is "notes"
---@field todos? string Todo directory name, default is "todos"
---@field journals? string Journal directory name, default is "journals"
---@class Dotmd.Config.Templates
---@field notes? fun(name: string): string[]
---@field todos? fun(date: string): string[]
---@field journals? fun(date: string): string[]
---@field inbox? fun(date: string): string[]
{
root_dir = "~/dotmd",
default_split = "none",
rollover_todo = {
enabled = false,
heading = { "Tasks" },
},
picker = nil,
dir_names = {
notes = "notes",
todos = "todos",
journals = "journals",
},
templates = {
notes = function(title)
return {
"---",
"title: " .. title,
"created: " .. os.date("%Y-%m-%d %H:%M"),
"---",
"",
"# " .. title,
"",
}
end,
todos = function(date)
return {
"---",
"type: todo",
"date: " .. date,
"---",
"",
"# Todo for " .. date,
"",
"## Tasks",
"",
}
end,
journals = function(date)
return {
"---",
"type: journal",
"date: " .. date,
"---",
"",
"# Journal Entry for " .. date,
"",
"## Highlights",
"",
"## Thoughts",
"",
"## Tasks",
"",
}
end,
inbox = function()
return {
"---",
"type: inbox",
"---",
"",
"# Inbox",
"",
"## Quick Notes",
"",
"## Tasks",
"",
"## References",
"",
}
end,
},
}
๐ Quick Start
See the example below for how to configure dotmd.nvim.
{
"y3owk1n/dotmd.nvim",
cmd = {
"DotMdCreateNote",
"DotMdCreateTodoToday",
"DotMdCreateJournal",
"DotMdInbox",
"DotMdNavigate",
"DotMdPick",
"DotMdOpen",
},
event = "VeryLazy",
---@type DotMd.Config
opts = {
root_dir = "~/dotmd" -- set it to your desired directory or remain at it is
default_split = "float" -- or "vertical" or "horizontal" or "none" based on your preference
rollover_todo = {
enabled = true, -- enable rollover
},
picker = "snacks" -- or "fzf" or "telescope" or "mini" based on your preference
},
keys = {
{
"<leader>nc",
function()
require("dotmd").create_note()
end,
desc = "[DotMd] Create new note",
},
{
"<leader>nt",
function()
require("dotmd").create_todo_today()
end,
desc = "[DotMd] Create todo for today",
},
{
"<leader>ni",
function()
require("dotmd").inbox()
end,
desc = "[DotMd] Inbox",
},
{
"<leader>nj",
function()
require("dotmd").create_journal()
end,
desc = "[DotMd] Create journal",
},
{
"<leader>np",
function()
require("dotmd").navigate("previous")
end,
desc = "[DotMd] Navigate to previous todo",
},
{
"<leader>nn",
function()
require("dotmd").navigate("next")
end,
desc = "[DotMd] Navigate to next todo",
},
{
"<leader>no",
function()
require("dotmd").open({
pluralise_query = true, -- recommended
})
end,
desc = "[DotMd] Open",
},
{
"<leader>sna",
function()
require("dotmd").pick()
end,
desc = "[DotMd] Everything",
},
{
"<leader>snA",
function()
require("dotmd").pick({
grep = true,
})
end,
desc = "[DotMd] Search everything grep",
},
{
"<leader>snn",
function()
require("dotmd").pick({
type = "notes",
})
end,
desc = "[DotMd] Search notes",
},
{
"<leader>snN",
function()
require("dotmd").pick({
type = "notes",
grep = true,
})
end,
desc = "[DotMd] Search notes grep",
},
{
"<leader>snt",
function()
require("dotmd").pick({
type = "todos",
})
end,
desc = "[DotMd] Search todos",
},
{
"<leader>snT",
function()
require("dotmd").pick({
type = "todos",
grep = true,
})
end,
desc = "[DotMd] Search todos grep",
},
{
"<leader>snj",
function()
require("dotmd").pick({
type = "journals",
})
end,
desc = "[DotMd] Search journal",
},
{
"<leader>snJ",
function()
require("dotmd").pick({
type = "journals",
grep = true,
})
end,
desc = "[DotMd] Search journal grep",
},
},
},
๐ฆ How It Works
dotmd.nvim organizes your Markdown files as follows:
dotmd/
โโโ inbox.md # Brain dump file
โโโ notes/ # Organized Markdown notes
โโโ todos/ # Date-based todo files (with rollover support)
โโโ journals/ # Date-based journal entries
Note Creation
When you create a new note, dotmd.nvim:
- Prompts for select/create a subdirectory or use the base directory.
- Prompts for a file name or path. (See Input patterns)
- Generates a file path inside the configured notes folder.
- Optionally applies a notes template.
- Opens the file in a vertical/horizontal split or current window.
Input patterns
- If the file name is not a path, it will be transformed and used as a file name and title.
- Input:
Amazing Idea - Output path:
amazing-idea.md - Output h1 heading:
# Amazing Idea
- Input:
- If the file name is a path, it will be used as a file path and the title will be transformed from the file name.
- Input:
amazing-idea.md - Output path:
amazing-idea.md - Output h1 heading:
# Amazing Idea
- Input:
- Support also nested directories during file creation (e.g.
project/idea.md)- Input:
project/idea.md - Output path:
project/idea.md - Output h1 heading:
# Idea
- Input:
- Weird enough, something like this will work too
project/Amazing Idea->project/amazing-idea.mdproject/amazing-idea->project/amazing-idea.md
Todo Files
When you create a new todo file, dotmd.nvim:
- Checks if today's todo file exists (e.g.
todos/2025-04-09.md). - If the file doesn't exist, prompt for create confirmation.
- If confirm, rolls over unfinished
- [ ] tasks from the previous filefrom the nearest previous todo file (if any and enabled). - Applies the todo template.
- Opens the file for
Related Skills
node-connect
347.2kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
108.0kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
347.2kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
347.2kQQBot ๅฏๅชไฝๆถๅ่ฝๅใไฝฟ็จ <qqmedia> ๆ ็ญพ๏ผ็ณป็ปๆ นๆฎๆไปถๆฉๅฑๅ่ชๅจ่ฏๅซ็ฑปๅ๏ผๅพ็/่ฏญ้ณ/่ง้ข/ๆไปถ๏ผใ
