A CLI tool for managing your markdown-based notes organized in notebooks with powerful SQL querying and automation capabilities.
Unlike basic note tools, OpenNotes provides:
- 🔍 SQL-Powered Search - Query notes using DuckDB's full SQL capabilities and markdown functions
- đź“‹ Intelligent Markdown Parsing - Extract structure, statistics, and metadata from markdown content
- 🤖 Automation Ready - JSON output designed for piping to jq, scripts, and external tools
- đź“” Multi-Notebook Organization - Manage multiple notebook contexts with smart auto-discovery
- 🎯 Developer-First - CLI-native, git-friendly, markdown-native, zero external runtime dependencies
- ⚡ Fast & Lightweight - Single compiled binary, in-process database, no setup required
go install github.com/zenobi-us/opennotes@latestRequires Go 1.24+. The binary will be placed in $GOPATH/bin/.
OpenNotes works best with your existing markdown files. No migration needed—just point it at your notes directory:
# Initialize with your existing markdown folder
opennotes notebook create "My Notes" --path ~/my-notes
# List all notes (instantly discovers your markdown files)
opennotes notes listExecute sophisticated queries against your entire notebook:
# Find all notes mentioning "deadline" (across entire notebook)
opennotes notes search --sql \
"SELECT file_path, content FROM read_markdown('**/*.md', include_filepath:=true) WHERE content ILIKE '%deadline%' LIMIT 5"
# Get word count statistics sorted by complexity
opennotes notes search --sql \
"SELECT file_path, (md_stats(content)).word_count as words FROM read_markdown('**/*.md', include_filepath:=true) ORDER BY words DESC LIMIT 10"
# Find checked-off tasks
opennotes notes search --sql \
"SELECT file_path FROM read_markdown('**/*.md', include_filepath:=true) WHERE content LIKE '%[x]%' ORDER BY file_path"All SQL queries return clean JSON—perfect for piping to jq, scripts, and external tools:
# Export statistics to JSON
opennotes notes search --sql "SELECT file_path, (md_stats(content)).word_count FROM read_markdown('**/*.md', include_filepath:=true)" | jq 'map({path: .file_path, words: .word_count})'
# Calculate totals across your notebook
opennotes notes search --sql "SELECT (md_stats(content)).word_count FROM read_markdown('**/*.md')" | jq 'map(.word_count) | {total: add, count: length, average: add/length}'
# Integrate with external tools
opennotes notes search --sql "SELECT file_path FROM read_markdown('**/*.md')" | jq -r '.[].file_path' | xargs wc -l- 🚀 Getting Started for Power Users - Complete 15-minute onboarding with examples
- 📚 SQL Query Guide - Full DuckDB markdown functions and patterns
- 🚀 Automation & JSON Integration - Advanced piping and external tool examples
- đź“‹ Notebook Discovery - Multi-notebook setup and context management
If you prefer to start simple:
-
Initialize a notebook:
opennotes init
-
Create a note:
opennotes notes add "My First Note" -
List notes:
opennotes notes list
-
Search notes:
opennotes notes search "keyword"
opennotes notebook- Display current notebook infoopennotes notebook list- List all notebooksopennotes notebook create <name>- Create a new notebook
opennotes notes list- List all notes in current notebookopennotes notes add <title>- Create a new noteopennotes notes remove <path>- Delete a noteopennotes notes search <query>- Search notes
Global configuration is stored in:
- Linux:
~/.config/opennotes/config.json - macOS:
~/Library/Preferences/opennotes/config.json - Windows:
%APPDATA%\opennotes\config.json
Each notebook has a .opennotes.json file with notebook-specific settings.
# Create a notebook
opennotes notebook create "Work"
# Add notes to your notebook
opennotes notes add "Team Meeting Notes"
opennotes notes add "Project Ideas"
# Search across notes
opennotes notes search "deadline"
# List all notes
opennotes notes listPerfect for new users and power user onboarding:
- Getting Started for Power Users - 15-minute complete onboarding
- Import existing markdown collections
- Execute SQL queries with practical examples
- Automate with JSON output and jq integration
- Build real-world workflows
For importing existing markdown collections:
- Import Workflow Guide - Step-by-step import process for all scenarios
- Prepare and import existing markdown
- Verify successful import
- Migration from Obsidian, Bear, generic markdown folders
- Troubleshooting common import issues
- Collection organization patterns (flat, hierarchical, multi-project)
From beginner to advanced SQL querying:
- SQL Quick Reference - Progressive learning path with 20+ practical examples
- Level 1: Basic queries (lists, counting, sorting)
- Level 2: Content search (LIKE, ILIKE, patterns)
- Level 3: Metadata analysis (word counts, statistics)
- Level 4: Complex queries (joins, aggregations)
- Practice exercises for each level
For complete documentation on available functions and advanced patterns:
- SQL Functions Reference - Complete DuckDB + markdown function reference
- SQL Guide - Comprehensive query patterns and best practices
- JSON Output Guide - Automation examples and tool integration
Manage multiple note collections with context-aware auto-discovery:
# View all registered notebooks
opennotes notebook list
# Switch context by directory (auto-discovers .opennotes.json)
cd ~/work/notes
opennotes notes list # Automatically uses work notebook
# Use notebook flag to specify a specific notebook
opennotes notes list --notebook "Personal"See Notebook Discovery for advanced multi-notebook workflows.
Interested in contributing? See CONTRIBUTING.md for development setup, code style guidelines, and how to submit pull requests.
MIT License. See LICENSE for details.
