Skip to content

eladab/znote

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

znote

znote

A terminal-native note-taking system. Fuzzy-search the contents of every note, follow [[wiki]]-style links between them, and view your whole notes graph in the browser — all without leaving the terminal.

┌────────────────────────────────────────────────────────────────────────┐
│ > graph                                                                │
│   physics_notes.md           │  1: # Physics Notes                     │
│   graph_theory.md            │  2:                                     │
│   cytoscape_layouts.md       │  3: See [[graph_theory]] for the        │
│ ▌ notes_on_clustering.md     │  4: clustering algorithms used in       │
│   ...                        │  5: [cytoscape layouts](cytoscape_…).   │
│                              │                                         │
│ Ctrl-D delete │ Ctrl-C copy first match │ Ctrl-P graph view            │
└────────────────────────────────────────────────────────────────────────┘

Highlights

  • Fast full-text fuzzy search across all notes via fzf + ripgrep, backed by a local content index so it stays instant even when your notes live in iCloud / Dropbox / OneDrive (no per-launch cloud download).
  • Live preview of each note as you type, with your query highlighted inline in the full file content.
  • Create-on-the-fly: type a query that doesn't match, press Enter, and you're editing a new .md file named after your query.
  • Inter-note links, two notations:
    • [[wiki-style]] / [[target|alias]] / [[subdir/target]]
    • [label](file.md) standard markdown Press <CR> or gf on a link in vim to jump to it. Broken links auto-create the missing note on follow.
  • In-vim insert-mode link picker: in insert mode, type [[ and an fzf overlay pops up listing every note. Selecting one inserts the stem inside [[…]] and leaves your cursor past the closing brackets in insert mode.
  • Backlinks via :ZnoteBacklinks — populates quickfix with every note that links to the current one.
  • Interactive graph view (Ctrl-P from the fzf list): launches a local HTTP server and opens a browser with a force-directed graph of your notes (Cytoscape.js + cola layout, organic Poisson-disk initial layout, click a node to read the rendered markdown in a modal). The server auto-shuts when the tab is closed.
  • Delete + copy bindings built into the picker (Ctrl-D, Ctrl-C).
  • Cloud-sync friendly: point NOTES_DIR at any synced folder (iCloud Drive, Dropbox, Google Drive, …) and edit from any device.

Install

One-liner (clone + install)

git clone https://github.com/eladab/znote.git
cd znote
./install.sh

Installs znote to /usr/local/bin (or ~/.local/bin if /usr/local/bin isn't writable). Override the destination with PREFIX=…:

PREFIX=$HOME/.local ./install.sh

Skip the first-run prompt by pre-seeding the notes directory:

ZNOTE_NOTES_DIR=$HOME/Documents/Notes ./install.sh

(ZNOTE_NOTES_DIR is a dedicated installer var so an exported runtime NOTES_DIR in your shell doesn't accidentally clobber an existing config.)

Manual

cp znote /usr/local/bin/znote
chmod +x /usr/local/bin/znote

Requirements

  • fzf ≥ 0.30 (uses --bind change:reload, start:reload)
  • ripgrep (rg)
  • vim 8.2+ with +terminal and +popupwin (link picker)
  • python3 ≥ 3.7 (graph server)
  • gawk (GNU awk; the main loop uses gensub)

Install on macOS:

brew install fzf ripgrep gawk vim python3

Debian/Ubuntu:

sudo apt install fzf ripgrep gawk vim python3

Arch:

sudo pacman -S fzf ripgrep gawk vim python3

Configuration

On first run, znote asks for your notes directory and saves it to:

~/.config/znote/config       # or $XDG_CONFIG_HOME/znote/config

To change it later, edit the file, delete it to re-prompt, or export NOTES_DIR in your shell (the env var always wins):

export NOTES_DIR="$HOME/Documents/Notes"

The config file is a sourceable shell snippet:

NOTES_DIR=/Users/you/Documents/Notes

Usage

Just run:

znote

Picker keybindings

Key Action
Enter Open selected note in vim, jumping to first match if a query was typed
Enter (query, no match) Create a new note named after the query (.md added, spaces → _)
Ctrl-D Delete the selected file (with confirmation)
Ctrl-C Copy the first matching line to clipboard
Ctrl-P Open the graph view in your browser
Esc Exit

In-vim keybindings (active in *.md files under $NOTES_DIR)

Key Action
<CR> / gf (normal) Follow link under cursor ([[wiki]] or [label](file.md))
[[ (insert) Open an fzf overlay listing all notes; select to insert the link
<C-o> Jump back (vim's built-in jumplist)
:ZnoteBacklinks Populate quickfix with notes linking to the current note

These bindings live in ~/.cache/znote/znote.vim, which znote regenerates on every launch and sources via vim -S. They are only active when vim is launched through znote (or znote --resolve triggered from within such a session). Opening a note with plain vim foo.md won't enable them — by design, znote stays out of your normal vim sessions.

If you want them everywhere, source the cached file from your ~/.vimrc:

if filereadable(expand('~/.cache/znote/znote.vim'))
  source ~/.cache/znote/znote.vim
endif

(Run znote at least once first to generate the file.)

Link syntax

Wiki style: see [[work_log]] for context.
Aliased:    refer to [[work_log|yesterday's notes]].
Nested:     subdir: [[projects/q3_plan]].

Markdown:   see [my work log](work_log.md).
Nested:     see [Q3 plan](projects/q3_plan.md).

Broken [[wiki]] targets auto-create as $NOTES_DIR/<target>.md (spaces become underscores). Bare basenames resolve against the index — if multiple files share a basename, the first alphabetically wins with a warning.

Graph view

Ctrl-P from the picker spawns a small Python HTTP server on a free port in 8765–8775 and opens http://127.0.0.1:<port>/ in your browser.

  • Force-directed layout (cola), Poisson-disk initial placement → organic spread
  • Click a node → rendered markdown in a modal; links inside the modal stay clickable
  • Live search box, zoom controls, shuffle button (re-randomize layout)
  • Server auto-shuts seconds after the tab closes (SSE-based detection), or after 30 min idle as a fallback
  • Force-stop with znote --graph-stop

How it works

znote keeps a tab-separated content index at ~/.cache/znote/index (relpath\tlineno\tcontent) which is rebuilt in the background on every launch. All foreground operations (search, preview, jump-to-line, backlinks) read from the index, so they never touch the source files — important when your notes live in iCloud Drive with "Optimize Storage" enabled and most files are dataless placeholders. The index is also kept in sync incrementally: after every edit in vim, the touched file is re-indexed; Ctrl-D removes the deleted file from the index immediately.

Subcommands

These are mostly used internally by znote but are documented for the curious:

Command Purpose
znote Interactive picker (the main UI)
znote --build Rebuild the content index
znote --search <q> Print matching file paths (used by fzf)
znote --preview <q> <file> Preview content with query highlighted
znote --jump <q> <file> Print the first matching line number
znote --resolve <target> Resolve a wiki-link target to an absolute path
znote --backlinks <basename> Emit file:line:text for every link to <basename>
znote --graph Start the graph server and open the browser
znote --graph-stop Stop the graph server
znote --index-update <file> Re-index a single file (used after vim exits)
znote --index-remove <file> Drop a file from the index (used after delete)
znote --write-vim Regenerate ~/.cache/znote/znote.vim

License

MIT — see LICENSE.

About

Zero-friction note taking

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages