Home
Softono
grove

grove

Open source Emacs Lisp
57
Stars
6
Forks
7
Issues
2
Watchers
1 month
Last Commit

About grove

An Obsidian-like note-taking mode for Emacs

Platforms

Web Self-hosted

Languages

Emacs Lisp

Links

+title: grove.el

+author: Jonathan Chu

+html:

An Obsidian-like note-taking mode for Emacs. One keybinding opens a full workspace with a file tree sidebar and your org notes.

[[file:grove-screenshot.png]]

[[https://melpa.org/#/grove][https://melpa.org/packages/grove-badge.svg]] [[https://img.shields.io/badge/license-GPL--3.0-blue.svg]]

  • Features
  • File tree sidebar with expand/collapse, indent guides, current file tracking, item counts, optional nerd font icons, and note preview on navigation
  • Quick capture — just type, first line becomes the title, saved to your inbox
  • Wikilinks — =[[note title]]= syntax with font-lock, click to follow, create on missing
  • Backlinks — ripgrep-powered, computed on demand, displayed in a side panel
  • Daily notes — one keybinding for today, yesterday, or tomorrow
  • Search — full-text ripgrep search with optional Consult integration
  • Tag search — find notes by =#hashtag= or org =:tag:= syntax
  • Inbox review — triage untagged notes
  • Graph view — visualize note connections via Graphviz

No database. No external Emacs dependencies. Just org files, a directory, and ripgrep.

  • Requirements

Optional:

  • Installation

** MELPA

Grove is available on [[https://melpa.org/#/grove][MELPA]]. After [[https://melpa.org/#/getting-started][adding MELPA]] to your package archives:

+begin_src emacs-lisp

(use-package grove :ensure t :bind-keymap ("C-c v" . grove-command-map) :custom (grove-directory "~/notes/") :config (global-grove-mode 1))

+end_src

=global-grove-mode= activates =grove-mode= in any org buffer that lives inside =grove-directory=, which enables wikilink font-locking and the =C-c C-l= keybinding for inserting links. Omit it if you'd rather enable =grove-mode= manually per buffer.

** Manual

Clone the repository and add it to your load path:

+begin_src emacs-lisp

(use-package grove :load-path "~/path/to/grove" :bind-keymap ("C-c v" . grove-command-map) :custom (grove-directory "~/notes/") :config (global-grove-mode 1))

+end_src

  • Usage

Set your vault directory and press =C-c v v= to open the workspace.

| Key | Command | Description | |-----------+----------------------+--------------------------| | =C-c v v= | =grove-open= | Open the grove workspace | | =C-c v q= | =grove-close= | Close and restore layout | | =C-c v n= | =grove-capture= | Quick capture a new note | | =C-c v f= | =grove-find= | Find note by title | | =C-c v s= | =grove-search= | Full-text ripgrep search | | =C-c v d= | =grove-daily= | Open today's daily note | | =C-c v b= | =grove-backlinks= | Show backlinks for note | | =C-c v t= | =grove-search-tag= | Search by tag | | =C-c v i= | =grove-inbox-review= | Triage untagged notes | | =C-c v l= | =grove-link-insert= | Insert a wikilink | | =C-c v g= | =grove-graph= | Show vault graph |

** Tree sidebar

| Key | Action | |-------------+-------------------------------| | =RET= | Open file / toggle dir | | =TAB= | Toggle directory expand | | =n= / =C-n= | Next entry (with preview) | | =p= / =C-p= | Previous entry (with preview) | | =g= | Refresh tree | | =q= | Close sidebar |

** Capture

=C-c v n= opens =grove-capture=, a blank org buffer. Type freely — no prompts, no template. The first line becomes the title; everything below becomes the body.

  • =C-c C-c= saves to the inbox
  • =C-c C-k= discards

For example, typing:

+begin_src org

Project ideas for next quarter

  • migrate to ripgrep
  • add a graph view

    +end_src

and pressing =C-c C-c= writes =inbox/project-ideas-for-next-quarter.org=:

+begin_src org

,#+title: Project ideas for next quarter

  • migrate to ripgrep
  • add a graph view

    +end_src

Filenames are derived from the title (lowercased, spaces to dashes). A numeric suffix is appended on collision.

** Inbox review

=C-c v i= opens =grove-inbox=, a triage buffer that lists notes needing attention. The buffer groups notes by the reason they showed up — currently, Untagged: notes with no =#+filetags:= line and no inline =#hashtags=.

| Key | Action | |-------------+------------------------------| | =RET= | Visit the note at point | | =n= / =p= | Move to next / previous line | | =g= | Refresh the buffer | | =q= | Close the buffer |

The intended workflow is short loops: open the inbox, jump into a note with =RET=, add tags or wikilinks, save, and either come back with =C-c v i= or refresh in place with =g=. Notes drop off the list as you tag them, so the buffer doubles as a progress indicator.

The list is built from the vault cache, so it covers your whole vault — not just files under =grove-inbox-directory=. Tag a note anywhere and it disappears from the next refresh.

** Graph

=C-c v g= renders a graph of all notes and their =[[wikilinks]]= using Graphviz. Requires =dot= on your PATH.

The graph display adapts to your frame width — on wide frames (160+ columns) it opens as a right side panel, otherwise it uses a full buffer. You can override this with =grove-graph-display=: ='side=, ='buffer=, or ='auto= (default).

Use =+= / =-= to zoom in/out and =0= to fit to window.

  • Configuration

+begin_src emacs-lisp

;; Required: set your vault directory (setq grove-directory "~/notes/")

;; Optional: customize subdirectories (defaults shown) (setq grove-inbox-directory "inbox") (setq grove-daily-directory "daily")

;; Optional: daily note filename format (default shown) (setq grove-daily-format "%Y-%m-%d")

;; Optional: tree sidebar width (default shown) (setq grove-tree-width 30)

;; Optional: show nerd font icons in the tree sidebar (setq grove-tree-icons t)

;; Optional: graph view settings (defaults shown) (setq grove-graph-layout "neato") ; or "dot", "fdp", "sfdp" (setq grove-graph-display 'auto) ; or 'side, 'buffer (setq grove-graph-min-width 160) ; frame width threshold for auto

+end_src

  • License

GPL-3.0. See [[file:LICENSE][LICENSE]].