Plugins
Emacs packages built on Org that org-lsp does as well, each as close to the package as Org itself: their options and commands are the package's, checked against Emacs with the package loaded, by recorded cases and differential fuzzing. Each is off until its option turns it on, in the shared configuration file or in an editor's settings, as the other options are; configuration.org lists their options with the others.
- org-super-agenda
- the agenda in groups (
org_super_agenda_mode). - org-roam
- a network of notes (
org_roam_enabled). - org-journal
- a journal, a file a day (
org_journal_enabled). - org-bullets
- headline stars shown as bullets (
org_bullets_mode).
Agenda groups (org-super-agenda)#
The agenda can group its lines as org-super-agenda does: each day of the
agenda, and each other view, is shown in groups, each under a header, in
place of one list. It is off until org_super_agenda_mode is true; groups
alone do nothing, as in Emacs, where org-super-agenda-mode turns it on.

org_super_agenda_groups is org-super-agenda-groups: a list of groups,
each a set of selectors with their arguments. Emacs's
(setq org-super-agenda-groups
'((:name "Today" :time-grid t :todo "TODAY")
(:name "Important" :priority "A")
(:order-multi (2 (:name "Shopping in town" :and (:tag "shopping" :tag "@town"))
(:name "Food-related" :tag ("food" "dinner"))))
(:name "Waiting" :todo "WAIT" :order 8)
(:priority<= "B" :order 1)
(:auto-category t :order 9)))
(org-super-agenda-mode)is, in the configuration file:
org_super_agenda_mode = true
[[org_super_agenda_groups]]
name = "Today"
time-grid = true
todo = "TODAY"
[[org_super_agenda_groups]]
name = "Important"
priority = "A"
[[org_super_agenda_groups]]
order-multi = [2,
{ name = "Shopping in town", and = ["tag", "shopping", "tag", "@town"] },
{ name = "Food-related", tag = ["food", "dinner"] }]
[[org_super_agenda_groups]]
name = "Waiting"
todo = "WAIT"
order = 8
[[org_super_agenda_groups]]
"priority<=" = "B"
order = 1
[[org_super_agenda_groups]]
auto-category = true
order = 9A group is an object of selectors, in the order Emacs's plist has them, or
a list of selectors and arguments in turn (["name", "Today", "time-grid",
true]), which can name a selector twice, as (:tag "a" :tag "b") does.
true is t, false is nil, and the words a selector takes (past,
today, todo, reverse …) are strings. "name" = false is Emacs's
:name none: a group with no header. A separator option of one character
(org_super_agenda_header_separator = "=") is Emacs's character (?=),
repeated across the window.
The same in an editor's settings, for Neovim:
require('org-lsp').setup({
settings = {
org_super_agenda_mode = true,
org_super_agenda_groups = {
{ name = 'Today', ['time-grid'] = true },
{ 'name', 'Important', 'priority', 'A' },
{ ['auto-category'] = true, order = 9 },
},
},
})A Lua table with keys has no order, so a group with several selectors
whose order matters is better written as a list, as Important is. In VS
Code's settings.json and Sublime Text's settings, a JSON object keeps
its order:
{
"org-lsp.settings": {
"org_super_agenda_mode": true,
"org_super_agenda_groups": [
{ "name": "Today", "time-grid": true, "todo": "TODAY" },
{ "auto-category": true, "order": 9 }
]
}
}A custom command or one of its blocks can have groups of its own, in its
settings, as Emacs's ((org-super-agenda-groups '(…))) does:
[[org_agenda_custom_commands]]
key = "u"
description = "Grouped"
blocks = [
{ type = "agenda", settings = { org_agenda_span = "day", org_super_agenda_groups = [
{ name = "Today", time-grid = true },
] } },
{ type = "alltodo", settings = { org_super_agenda_groups = [
{ auto-todo = true },
] } },
]The selectors are those of org-super-agenda 1.4:
- Dates
date,time-grid,deadline,scheduled,effort<,effort>- Entries
anything,children,habit,file-path,log,heading-regexp,regexp,property,tag,category,todo,priority,priority>,priority>=,priority<,priority<=- Groups of their own
auto-category,auto-dir-name,auto-group,auto-outline-path,auto-parent,auto-planning,auto-priority,auto-property,auto-tags,auto-todo,auto-ts,ancestor-with-todo- Combining
and,not,discard,take,order-multi,order
The selectors that run Emacs Lisp, pred, auto-map, transformer and
property with a function, are refused with a message in the view: there
is no Lisp to run. face is left out: the lines keep their own faces. The
other options are Emacs's: org_super_agenda_unmatched_name,
org_super_agenda_unmatched_order, org_super_agenda_header_separator,
org_super_agenda_header_prefix, org_super_agenda_final_group_separator,
org_super_agenda_date_format, org_super_agenda_hide_empty_groups,
org_super_agenda_keep_order, org_super_agenda_group_property_name and
org_super_agenda_properties_inherit.
Emacs loads org-habit when it loads org-super-agenda, which then draws
habits' consistency graphs; org-lsp draws them only with org-habit in
org_modules. The habit selector works either way.
Notes (org-roam)#
A directory of notes can be worked on as org-roam does: each file, and
each entry with an ID property, is a node; nodes are found by their
titles and aliases (ROAM_ALIASES), linked to with id: links, and made
with capture templates of their own. It is off until org_roam_enabled is
true, in the configuration file or in an editor's settings, as the other
options are:
org_roam_enabled = true
org_roam_directory = "~/notes"require('org-lsp').setup({
settings = { org_roam_enabled = true, org_roam_directory = '~/notes' },
})The commands are org-roam's:
org.roam.node.findorg-roam-node-find: asks for a node (Node, completed from the titles and aliases, those of the files changed last first, asorg_roam_node_display_templateshows them) and visits it; a title no node has makes a new node, with a capture.org.roam.node.insertorg-roam-node-insert: the same question, then a link to the node,[[id:…][title]], at the cursor; withorg_roam_node_formatter, a template asorg_roam_node_display_templateis, the description is the node as it formats it ("${title} (${file})"). On a selection, the selection is what is typed first and the link's description, and the link takes its place. A new node is linked to once its capture is filed.org.roam.captureorg-roam-capture: the same question, then a capture to the node: to its file for a node that exists.org.roam.node.randomorg-roam-node-random: visits a node picked at random.org.roam.alias.add,org.roam.alias.removeorg-roam-alias-addandorg-roam-alias-remove: an alias of the node at the cursor (the entry with anIDthat holds it, or the file's) added to itsROAM_ALIASES(Alias), or one picked among them taken out (Remove).org.roam.ref.add,org.roam.ref.removeorg-roam-ref-addandorg-roam-ref-remove: the same for itsROAM_REFS(Ref, Remove).org.roam.ref.findorg-roam-ref-find: visits the node of a reference picked among the nodes' references (Ref), as org-roam keeps them: a URL without its scheme (//example.com), a citation key without@. When nodes share a reference, the first one's is visited.org.roam.promote,org.roam.demoteorg-roam-promote-entire-bufferandorg-roam-demote-entire-buffer: a file of one top-level headline made the file's node (its title in#+title:, its tags in#+filetags:, the other headlines a level up), or back. Without a#+title:, demoting fails as in Emacs, but leaves the file as it was.org.roam.refileorg-roam-refile: the subtree at the cursor moved under a node picked (Node), a level below it, after its subtree; to a file's node, at the end of the file. Before the first headline the whole file goes, its node made a headline first, and the file is deleted when the editor can delete files (else it is left empty). The selection is not refiled instead of the subtree, as it is in Emacs.org.roam.graphorg-roam-graph: the nodes and the links between them drawn by Graphviz (org_roam_graph_executable,dot), then shown byorg_roam_graph_viewer, or opened as the system opens the file. With a count, only the nodes connected to the one at the cursor:C-u(4) any number of steps away, another count that many nodes along the way (1the node and its own links). Where Emacs says nothing when Graphviz fails, org-lsp shows what it wrote;org-roam-graph-link-builderis always org-roam's (anorg-protocol://roam-nodelink).org.roam.extractorg-roam-extract-subtree: the subtree at the cursor, given anIDunless it has one, moved to a new file (Extract node to:, relative toorg_roam_directory, offered asorg_roam_extract_new_file_pathnames it) where its headline is the file's node. In the name offered,${title},${slug}and${id}are the node's, and other${…}are left for you to replace rather than asked for. Unlike Emacs, which asks the questions oforg-capture-fill-templatewhile it fills the name, org-lsp refuses a name that asks one (%^{…},%^t), saying so.org.roam.tag.add,org.roam.tag.removeorg-roam-tag-addandorg-roam-tag-remove: tags, separated by colons, added to the node or taken out (Tag): on its headline, or in#+filetags:for the file's node. They are offered from the tags of the nodes andorg_tag_alist, or from the node's own.
These commands have no keys, as in Emacs: run them from the editor's command list, or give them keys of your own.
The org-roam buffer shows what links to a node:

org.roam.buffer.toggleorg-roam-buffer-toggle(C-c n lin theemacspreset,<Leader>nlin thevimone): shows the buffer beside the file, for the node at the cursor, or hides it. While it shows, it follows the node the cursor is in, in org-roam's files.org.roam.buffer.dedicatedorg-roam-buffer-display-dedicated: a buffer of its own for a node asked for (Node), which stays on that node; with a count (C-u), the node at the cursor.org.roam.buffer.refreshorg-roam-buffer-refresh: the buffer again, with what the files say now.
Its sections are those of org_roam_mode_sections: Backlinks, the nodes
whose id: links lead to the node, Reflinks, those that link to or cite
one of its ROAM_REFS, and Unlinked References, the lines of org-roam's
files that name its title or an alias without a link. Each item is the
node it comes from, its outline path, and the text around the link, as
org-roam-preview-default-function shows it; an unlinked reference is its
file, line, column and the line itself.
A roam: link names a node by its title or an alias, [[roam:A note]].
Following it (org.open) visits the node, the link first turned into an
id: link to it; a title no node has makes a node, as finding one does.
With org_roam_link_auto_replace (on by default), saving one of org-roam's
files turns its roam: links to nodes into id: links. In those files,
completion in a link, [[, [[roam: or [[id:, offers the titles and
aliases of the nodes, and the one picked becomes [[id:…][title]]; with
org_roam_completion_everywhere, the word at the cursor is completed so
too.
A new node is captured with org_roam_capture_templates, whose default is
org-roam's: a file of its own named after the time and the title's slug,
which starts with the title:
[[org_roam_capture_templates]]
key = "d"
description = "default"
type = "plain"
template = "%?"
target = ["file+head", "%<%Y%m%d%H%M%S>-${slug}.org", "#+title: ${title}\n"]
unnarrowed = trueThey are written as org_capture_templates, with org-roam's targets
(file, file+head, file+olp, file+head+olp and node); a path is
relative to org_roam_directory. Besides the escapes of capture templates,
their texts and paths may have ${title}, ${slug} and ${id} of the new
node, and ${name} for any other name, which is asked for once (name);
${name=default} starts the answer with default. With one template it is
used at once; with more, its key is asked for. The capture buffer shows
what goes into the target: with unnarrowed, the whole file, its ID and
head too. The node's file is written when the capture is filed
(org.capture.finish), and the link of org.roam.node.insert goes in then.
Daily notes are org-roam-dailies': a file a day in org_roam_dailies_directory
(daily/ under org_roam_directory), made with
org_roam_dailies_capture_templates, whose default is an entry in a file
named after the day:
[[org_roam_dailies_capture_templates]]
key = "d"
description = "default"
type = "entry"
template = "* %?"
target = ["file+head", "%<%Y-%m-%d>.org", "#+title: %<%Y-%m-%d>\n"]%<…> and the other escapes of time are the note's day. The commands, under
C-c n d as org-roam's manual binds them:
org.roam.dailies.capture.todayorg-roam-dailies-capture-today(n): a capture to today's note; withC-u, the note itself.org.roam.dailies.goto.todayorg-roam-dailies-goto-today(d): the note of today, made with itsIDand head if it is not there.org.roam.dailies.goto.tomorrow,org.roam.dailies.goto.yesterday- (
t,y) the note a day on or back, or as many days as the count; theircapturerelatives capture to it. org.roam.dailies.capture.date,org.roam.dailies.goto.date- (
v,c) the note of a date picked in the date prompt's calendar, which marks the days with a note, or typed as Org's date prompt reads it, a day without a year in this year even when it has passed (Capture to daily-note, Find daily-note). WithC-u,capture.dategoes to the note. org.roam.dailies.goto.next,org.roam.dailies.goto.previous- (
f,b) from a daily note, the next or previous one there is, or as many on as the count: Already at newest note at the last. org.roam.dailies.find.directoryorg-roam-dailies-find-directory(.): the notes of the directory, those of the directories in it too, in the order of their names, to pick one and visit it.
The server keeps no database: it reads the files of the directory when a
command needs them, again when they have changed, in the editor or on
disk, and they are what org-roam-db-sync would make of them, checked
against Emacs by recorded cases and differential fuzzing. What differs:
- Encrypted files (
.gpg,.age) are not read. - The node lines are made for a window 79 columns wide, as Emacs's are in
a frame of 80;
${field:*}fills the rest of those. - A
file+datetreetarget is refused: daily notes are org-journal's (see A journal (org-journal)). - Aborting the capture of a new file (
org.capture.abort) asks nothing: the file was never written. - A capture whose target file changes in the editor before it is filed is refused; abort it and capture again.
- Tags go on the node's headline even when the database does not have the node yet (a node not saved, or in a file org-roam cannot read); Emacs then puts them on the line of the cursor.
- A link being typed is completed before its closing
]]is typed too, and its completions come with the usual ones of a link; Emacs completes only between[[and]], and only node titles there. After[[id:the titles are offered too, which org-roam leaves to Org. A title of several nodes is not offered (Emacs fails on it). - The org-roam buffer is an Org file: its items are headings linking to
the place they come from, which
org.openvisits, and their previews are the text, not shown as Emacs shows it in a section of its own. - The persistent buffer follows the cursor only in editors that report its
moves (Neovim, Vim, VS Code, Sublime Text); in the others it changes
with
org.roam.buffer.toggleororg.roam.buffer.refresh. - Unlinked references are found by the server itself, as ripgrep finds
them for org-roam (its PCRE pattern, word boundaries, any case), so no
rgis needed; encrypted files are not searched. org-id-locations-fileis read, never written: anid:link is followed to the files open in the editor, the agenda files, the files Emacs listed there and org-roam's files.- What only Lisp can say is not there:
org-roam-node-formatteras a function, andorg-roam-db-node-include-function, which decides whether each node is one. The links of keyword lines and property drawers followorg_roam_db_extra_links_elementsandorg_roam_db_extra_links_exclude_keys. - Going to a daily note that is not there writes it, its
IDand head in it; Emacs leaves its buffer unsaved. In Sublime Text, Zed and Helix, which show no date prompt, its date is typed. org-roam-dailies-find-directoryopens the directory in Dired, where the editors have no list of a directory's files to show for a server: its notes are offered to pick from instead, as the editor offers any choice.
A journal (org-journal)#
A journal can be kept as org-journal keeps it: a file a day in a
directory (or a file a week, month or year, org_journal_file_type), an
entry for each day under a headline with its date, and under it one for
each time something is written. It is off until org_journal_enabled is
true:
org_journal_enabled = true
org_journal_dir = "~/journal"require('org-lsp').setup({
settings = { org_journal_enabled = true, org_journal_dir = '~/journal' },
})The commands are org-journal's:
org.journal.new.entryorg-journal-new-entry(C-c j jin theemacspreset,<Leader>jjin thevimone): today's file, today's entry made if it is not there yet, and a new entry in it with the time (org_journal_time_format). With a count (C-u), today's entry only. The first entry of a day takes the items of the entry before it thatorg_journal_carryover_itemsmatches (TODO items unless set), with the headlines above them, out of that entry.org.journal.new.date.entryorg-journal-new-date-entry: the same for a date asked for (Date, as Org's date prompt reads it).org.journal.new.scheduled.entryorg-journal-new-scheduled-entry: a TODO entry for a day to come (Date), with its timestamp afterorg_journal_scheduled_string. With a count, an entry that is not a TODO.org.journal.next.entry,org.journal.previous.entryorg-journal-next-entry(C-c j f,<Leader>jf) andorg-journal-previous-entry(C-c j b,<Leader>jb), in a journal file: the entry of the day after the one at the cursor, or before, in whatever file it is.org.journal.open.currentorg-journal-open-current-journal-file: the file of today.org.journal.rescheduleorg-journal-reschedule-scheduled-entry, on an entry to come: it moves to the day asked for (Date), its time and timestamp changed for that day's.
The journal is searched, as search-forward searches, without regard to
case:
org.journal.searchorg-journal-search(C-c j s,<Leader>js): asks for the string (Enter a string to search for), then the first and the last day (Enter the search start, Enter the search end); with a count, every day.org.journal.search.forever,org.journal.search.futureorg-journal-search-foreverandorg-journal-search-future: every day, or from today on.org.journal.search.future.scheduledorg-journal-search-future-scheduled: the TODO entries from today on.
The results are a file of their own, org-journal-search.org: each line
is the day of an entry, which links to the line it was found on
(org.open follows it), and the line itself, in the order of
org_journal_search_results_order_by and with the dates of
org_journal_search_result_date_format. The entries to come with a
timestamp from now on are another one, org-journal-schedule.org:
org.journal.schedule.vieworg-journal-schedule-view.
The date prompt's calendar marks the days with an entry, as
org-journal-mark-entries does: before now, and to come.
The calendar also opens on its own, as M-x calendar shows it: with
org.goto.calendar (org-goto-calendar, C-c > in the emacs preset,
<Leader>o> in the vim one), on the day of the timestamp at the cursor or
the line's last active one, or today (with C-u, today). It moves with the
date prompt's keys and q closes it. org-journal's keys work in it, on the
day of its cursor, as in Emacs's calendar (in the vim preset under
<Leader>j, as j moves a week down):
j r,j dorg-journal-read-entry(org.journal.read.entry) andorg-journal-display-entry(org.journal.display.entry): the entry of the day, in another window;j dleaves the cursor in the calendar. No journal entry for this date. when it has none.],[org-journal-next-entryandorg-journal-previous-entry: the next or the previous day with an entry. org-journal then says No journal entry after this one (or before), even when it went to one, unlessorg_journal_follow_modeis on: the entry of that day then shows in another window (org-journal-follow-mode), the cursor staying in the calendar.j norg-journal-new-date-entry: an entry for the day, a TODO entry for a day to come.j morg-journal-mark-entries: the days with an entry marked again, after entries were made or removed.j s f,j s Forg-journal-search-foreverandorg-journal-search-future.j s w,j s m,j s yorg-journal-search-calendar-week,…-monthand…-year(org.journal.search.calendar.week…): a search of the day's week, month or year. org-journal's week runs from its first day to the first day of the next, ascalendar_week_start_daystarts them.
org_journal_follow_mode = true
Each shows the entry it is about, in its file, and with
org_journal_hide_entries_p (on by default) the other entries folded, as
org-journal leaves them. A new entry made from another file, and today's
file, show in another window, as org-journal-find-file-fn
(find-file-other-window) shows them; with
org_journal_find_file_fn = "find-file" they show where the command was
run. Zed and Helix show them where they show any file. A journal file that is not open is written to
disk; one that is open is changed in the editor, for it to save.
org_journal_enable_agenda_integration puts the files from yesterday on
in org_agenda_files, as org-journal-enable-agenda-integration does.
org-journal's files have no extension unless org_journal_file_format
gives them one (%Y%m%d.org). Neovim, Vim, VS Code and Sublime Text open
the files of org_journal_dir without an extension as Org files, as the
server tells them where it is. Zed and Helix are told ahead of time which
files are Org: add the directory there (here journal), or give the
files .org:
{ "file_types": { "Org": ["**/journal/*"] } }# ~/.config/helix/languages.toml, in the [[language]] of org
file-types = ["org", { glob = "journal/*" }]The commands are what org-journal does, checked against Emacs by recorded cases and differential fuzzing, its oddities too (an entry for a day before all the others goes first in its file). What differs:
- The keys are under
C-c j, the prefix org-journal's README suggests, rather than its default,C-c C-, whose keys are Org's. - A file that is not open is written to disk; Emacs leaves the buffer it changed unsaved.
- Folds close and open by headlines: a headline whose children show but whose text does not shows open.
- Folds open and close only in Neovim, Vim, VS Code and Sublime Text; in Zed and Helix the file shows as it does.
org-journal-encrypt-journal(files encrypted whole,.gpg) is not there: Emacs decrypts such a file in memory, where the editors would need it decrypted on disk, or a way of their own to read it.org_journal_enable_encryption, withorg-crypt, is there.org-journal-enable-cacheis not needed: it keeps the days with an entry in a file between sessions, so that Emacs reads only the files changed since, and gives the same days; the server reads the directory each time it needs them.- The calendar and its keys are in Neovim, Vim and VS Code, which show the
date prompt. An entry
j rshows is not read-only, asview-modemakes it in Emacs, and a search from the calendar does not show its first result beside the results. - The search results are an Org file whose dates are links, two blanks
before the line found where Emacs has a tab, in place of a buffer of
buttons (
n,p,TABmove between them, and the first result shows beside them); its matches are not highlighted. An empty string finds every entry with a time, which Emacs means to do but hangs on. - Dates are written as in the C locale:
%xis05/15/26and%AFridaywhatever the system's locale is. A journal Emacs kept under another locale (en_US.UTF-8writes05/15/2026) has headings org-lsp does not find; setorg_journal_date_formatto a format without%x, such as"%A, %m/%d/%Y", to match them.
Bullets (org-bullets)#
Headlines can show as org-bullets shows them: the last star of each is
drawn as a bullet, the one of its level in org_bullets_bullet_list (◉,
○, ✸, ✿, then again from the first), and the stars before it are
hidden in their place, as org_hide_leading_stars hides them. It is off
until org_bullets_mode is true:
org_bullets_mode = true
org_bullets_bullet_list = ["●", "○", "◆", "◇"]As org-bullets.nvim does, the -, + and * of list items show as
org_bullets_list_bullet (•), and the mark between the brackets of a
checkbox as the one org_bullets_checkboxes gives its state: [ ] and
[-] as they are, [✓] for [X] (org-bullets.nvim shows [˟] for
[ ]). false turns either off:
org_bullets_list_bullet = "–"
org_bullets_checkboxes = { todo = "˟", done = "✔" }The text does not change: the bullet is drawn in place of the star, as
pretty entities are, by the editor where it can (Neovim), else as an inlay
hint (VS Code, Zed, Helix); the leading stars are hidden where virtual
indentation can hide them (Neovim, VS Code). A bullet takes the colors of
what it stands for, as the composed character keeps the face of the star
in Emacs: the headline's level, the list's bullet, the checkbox's state.
That is in Neovim only: VS Code cannot give a decoration or an inlay hint
the colors of a token. As in Emacs, every line that starts with stars and
a space gets its bullet. What differs: org-bullets-face-name is not read
(the bullet keeps the headline's colors), clicking a bullet does not cycle
the headline, and inline tasks have no second bullet.