tdo is a opinionated, command line based note-taking system. Demo video
- Unified Note System: Manage daily todos, journal entries, and long-term notes in one organized system with intuitive navigation
- Natural Language Dates: Use expressions like
tomorrow,next-friday,2-weeks-ago, or2025-12-25instead of calculating offsets manually - Fuzzy Search: Interactive search powered by fzf with syntax highlighting to quickly find and review any note
- Git Integration: Automatically commits and backs up your notes with timestamps for seamless sync across devices
- Editor Flexibility: Works with any editor through
$EDITOR- vim, emacs, vscode, includes neovim integration - AI & Automation: Integrates with workflows, pipes, subshells, and AI agents through mcp-tdo
- ripgrep, fzf
- bat (optional, for syntax highlighting in search)
- coreutils (required on macOS, for gdate command)
git clone https://github.com/2kabhishek/tdo
cd tdo
./install.sh-
NOTES_DIRshould point to your notes directory -
TODOS_DIRoptional, should point to your todos directory, default:NOTES_DIR/todos -
JOURNAL_DIRoptional, should point to your journal directory, default:NOTES_DIR/entries -
EDITORset to your choice of editor
If you want to customize the setup or are facing issues with installation, you can set up tdo manually.
Change these commands according to your needs.
# Link tdo to a directory that's in PATH (~/.local/bin here)
ln -sfnv "$PWD/tdo.sh" ~/.local/bin/tdo
# Create a notes dir if not already present
mkdir -p $HOME/Projects/Notes
# Add the NOTES_DIR env var to your shell config ~/.bashrc, ~/.zshrc etc
echo "NOTES_DIR=$HOME/Projects/Notes" >> ~/.zshrc
# Add sample templates to your NOTES_DIR
cp -irv templates $NOTES_DIR
# Reload shell config
source ~/.zshrcIf you want to enable tab completion for tdo, add this to your shell's RC file (bashrc, zshrc, config.fish etc).
# zsh and bash
source /path/to/tdo/completions/tdo_completion.sh
# fish
source /path/to/tdo/completions/tdo_completion.fishThis will allow you to use tab completion to quickly access your notes when you type tdo <tab>.
If you want to sync your notes across devices, you can set up a git repo on the $NOTES_DIR and add GitHub/GitLab as remote.
cd $NOTES_DIR
git init
git add .
git commit -m 'init: notes'
git remote add origin <your-remote-git-url>
git push origin maintdo will automatically commit every change with a timestamp like 03 Feb 11:33 as commit message.
If you use Neovim, I highly recommend using tdo.nvim, it seamlessly integrates tdo and nvim and adds some useful features on top.
tdoto open today's todostdo <date_expression>to open todos with flexible date formats, e.g:tdo 1,tdo monday,tdo next-friday,tdo 2-weeks-later,tdo 2025-07-14tdo entry <date_expression>to open journal entry with same flexible date formats as todos, e.g:tdo e tomorrowtdo e last-tue,tdo e 1-year-agotdo <note_title>to open or create anote_tile.mdnote, use folder names to categorise notes, e.g:tdo tech/vim-tipstdo noteortdo nto create a new note with the current timestamp indraftstdo find <text>ortdo fto interactively search fortextin all your notestdo findwithout any search term to review all your notestdo todoortdo tto show all your pending todostdo pendingortdo pwill show count of pending todostdo commit <path>ortdo cto commit changes in path, happens automatically, needed for plugins and integrations
Run
tdo hto get more help info on the command line
tdo supports intuitive natural language date expressions for both todos and journal entries. This makes it easy to reference dates without calculating offsets manually.
Numeric Offsets:
- Positive numbers for future days:
1,7,30 - Negative numbers for past days:
-1,-7,-30
Basic Relative Dates:
today,tomorrow,yesterday
Weekdays:
sunday,monday,tuesday,wednesday,thursday,friday,saturdaynext-sunday,next-monday, etc. (next week's occurrence)last-sunday,last-monday, etc. (previous week's occurrence)- Short forms:
sun,mon,tue,wed,thu,fri,satnext-sun,last-mon, etc.
Quick Aliases:
next-week,last-week,next-month,last-month,next-year,last-year
Programmatic Patterns:
N-weeks-ago/N-weeks-later(e.g.,2-weeks-ago,3-weeks-later)N-months-ago/N-months-later(e.g.,1-month-ago,6-months-later)N-years-ago/N-years-later(e.g.,1-year-ago,2-years-later)
Absolute Dates:
YYYY-MM-DDformat (e.g.,2025-07-14)
tdo expects an opinionated directory structure to function.
- Notes live in the
notessub-dir, use these for long term knowledge management, second brain - Notes use the templates/note.md file as template
- Todos live in the
todossub-dir, use these for short term notes, daily todos - Todos use the templates/todo.md file as template
- Journal entries live in
entriessub-dir, use these for personal notes, life logging - Journal entries use the templates/entry.md file as template
βββ todos
βΒ Β βββ 2023
βΒ Β βββ 11
βΒ Β Β Β βββ 2023-11-29.md
βββ entries
βΒ Β βββ 2024
βΒ Β βββ 02
βΒ Β Β Β βββ 2024-02-03.md
βββ notes
βΒ Β βββ tech
βΒ Β Β Β βββ quit-vim.md
βΒ Β Β Β βββ arch-btw.md
βββ templates
Β Β βββ entry.md
Β Β βββ note.md
Β Β βββ todo.md
You can configure tdo by either defining environment variables or via a $HOME/.config/tdorc file.
ADD_ENTRY_TIMESTAMP[boolean]: Whether to add a time stamp when usingtdo entryortdo e.ADD_NEW_NOTE_TIMESTAMP[boolean]: Whether to add a time stamp when creating new notes withtdo <note_title>.FILE_NAME_AS_TITLE[boolean]: Whether to add the file name as title when creating new notes withtdo <note_title>. Iftrue, then it adds<note_title>as a markdown title in the first line of the new note.ENTRY_TIMESTAMP_FORMAT[string]: can be any bash string such as a date format expression. It is ignored ifADD_ENTRY_TIMESTAMPis set tofalse.NOTE_TIMESTAMP_FORMAT([string]: can be any bash string such as a date format expression. It is ignored ifADD_NEW_NOTE_TIMESTAMPis set tofalse.
ADD_ENTRY_TIMESTAMP=true
ADD_NEW_NOTE_TIMESTAMP=false
FILE_NAME_AS_TITLE=false
# Reads ## Mon, 12:00 PM
ENTRY_TIMESTAMP_FORMAT="## %a, %I:%M %p"
# Reads ## Fri. Apr 06, 2024 - 06:48 PM
NOTE_TIMESTAMP_FORMAT="## %a. %b %d, %Y - %I:%M %p"configs defined in
tdorcwill override corresponding environment variables
tdo includes comprehensive unit and integration tests to ensure reliability.
# Install bats-core (testing framework)
brew install bats-core # macOS
sudo apt-get install bats # Ubuntu/Debian
# Run all tests
bats tests/unit tests/integration- Unit Tests: Date parsing, file generation, utility functions
- Integration Tests: End-to-end workflows for todos, journal entries, and notes
- Mock System: Isolated testing with fixed dates and mocked external dependencies
All tests use a comprehensive mocking strategy to ensure consistent, predictable results across different environments and dates.
You tell me!
After trying out every note management system under the sun I had decided on using plain markdown notes powered by nvim2k.
tdo is a spiritual successor and complimentary tool to that, taking the same principles and making it more accessible and simple.
- cmtr β Fast git commits
- mkrepo β Spin up new GitHub repos from the CLI
- ghpm β Manage all your GitHub repos
- gsync β Sync your git repos
- dots2k β Dev Environment
- nvim2k β Personalized Editor
- sway2k β Desktop Environment
- qute2k β Personalized Browser
β hit the star button if you found this useful β
Source | Blog | Twitter | LinkedIn | More Links | Other Projects