Agenda
The agenda follows Emacs Org 9.8: the same entries, line layout, sorting and default options (the Emacs variable is named next to each option in lua/org/config/agenda.lua and org-config).
<prefix>a opens the dispatcher (org-agenda):
a agenda for the current week (oragenda.span) t global TODO list T TODO list for one keyword m tags/property match M match, TODO entries only s search for words or a regexp S like s, TODO entries only n agenda and all TODOs # stuck projects / multi-occur: a regexp in all agenda files andagenda.text_search_extra_files(org-agenda-multi-occur-extra-files), into the quickfix list < restrict to the current file / subtree (press again to cycle) > remove the restriction and the restriction lock e export the agenda views of custom commands (org-agenda-export) * toggle sticky agenda buffers (agenda.sticky) ? the :FLAGGED: entries of MobileOrg (org-mobile) ... custom commands fromagenda.custom_commands: the description (or a name for the type) and ": MATCH" (agenda.menu_show_matcher, org-agenda-menu-show-matcher);agenda.menu_two_columnslists them in two columns (org-agenda-menu-two-columns)
:Org agenda a|t [KW|KW]|T KW|m MATCH|M MATCH|s TEXT|S TEXT|n|#|/ REGEXP|
*>?|e|export FILE|day|week|fortnight|month|year|N|<key>|DATE
Restriction lock (org-agenda-set-restriction-lock): <C-c><C-x>< lock every agenda command to the current subtree (to the file when not under a headline, or with a count); also in the agenda, from the entry at point <C-c><C-x>> remove the lock The locked subtree is highlighted with OrgAgendaRestrictionLock (only its headline withagenda.restriction_lock_highlight_subtree = false, org-agenda-restriction-lock-highlight-subtree). Other keys in org buffers: <C-c>[ <C-c>] add the current file to / remove it from the agenda files (org-agenda-file-to-front, org-remove-file); a count (C-u) adds or moves it to the end instead of the front <C-'> <C-,> visit the next agenda file (org-cycle-agenda-files) :Org edit_agenda_file_list edit the list: the list file whenagenda_filesnames one, else a buffer with the list;:winstalls it (org-edit-agenda-file-list) Like Emacs, these changes are saved: whenagenda_filesis the name of a file listing the agenda files, that file is rewritten; otherwise the new list (directories and globs expanded to their files) is saved in stdpath("data")/org/agenda-files.json and replaces the configured list at startup for as long asagenda_filesin setup() keeps the value it was made from (Emacs saves it with Customize).
With the default agenda_files = {} (Emacs org-agenda-files nil) the agenda is empty, like in Emacs, until files are added with <C-c>[ or the option is set. A listed file that does not exist is asked about when an agenda is built: r removes it from the list (for the session), any other key aborts (org-check-agenda-file); agenda.skip_unavailable_files = true skips such files silently (org-agenda-skip-unavailable-files).
Agenda contents
For each day, per file, in this order (org-agenda-get-day-entries): - Deadlines, on their day (Deadline:) and in today's agenda fromdeadline_warning_days(or the-Ndwarning) before (In N d.:) and after (N d. ago:, foragenda.deadline_past_days). Done entries show on their day only. - Scheduled entries on their day (Scheduled:) and, while not done, in today's agenda (Sched.Nx:, foragenda.scheduled_past_days). A delay (-2d) hides the entry until it is over;scheduled_delay_days(org-scheduled-delay-days, 0) is the delay of entries without one, and a negative value applies to all of them. - Date ranges on each of their days ((2/3):), with the start time on the first day and the end time on the last. - Active timestamps. Repeaters show on every repeat up to today and, after today, peragenda.show_future_repeats(true, false, "next");agenda.prefer_last_repeatshows the last repeat instead of the base date. - Diary sexps,<%%(...)>timestamps and%%(...)lines (org-agenda-diary-sexp), including holidays (org-agenda-holidays). - Withagenda.include_diary, the entries of the Emacs diary file (org-agenda-diary-file). - Habits (:STYLE: habitand a repeater) in today's agenda, without a leader, with a consistency graph from columnagenda.habits.graph_column(40) that overwrites the end of the line (org-habit). - A time grid (agenda.time_grid, org-agenda-time-grid) with the current time; theremove-matchflag hides grid lines at the time of an entry. - Entries under ARCHIVE-tagged or COMMENT headlines are excluded (agenda.skip_comment_trees = falsekeeps COMMENT trees).agenda.skip_function_global(headline)returning true leaves an entry out of every view, built-in ones included (org-agenda-skip-function-global).agenda.entry_typesselects the kinds ("deadline", "scheduled", "timestamp", "sexp"; "deadline*" / "scheduled*" keep only timed ones). Skipping:skip_scheduled_if_done,skip_deadline_if_done,skip_timestamp_if_done,skip_scheduled_if_deadline_is_shown(true or "not-today"),skip_timestamp_if_deadline_is_shown,skip_scheduled_repeats_after_deadline,skip_additional_timestamps_same_entry,skip_deadline_prewarning_if_scheduled(true: no pre-warning when the entry is scheduled; N: warn N days before; "pre-scheduled": not before the scheduled date),skip_scheduled_delay_if_deadline.show_all_dates = falsehides days without entries.
Line format
Each line isagenda.prefix_format(org-agenda-prefix-format) followed by the headline and its tags: agenda " %i %-12:c%?-12t% s" todo, tags, search " %i %-12:c" %c category %i icon (agenda.category_icons) %t time of day %s leader (Scheduled:, In 3 d., ...) %e effort %l level (spaces) %b breadcrumbs (outline path +breadcrumbs_separator) %T last tag %(expr) a Lua expression, withitemandhlA width like%-12pads (no truncation),%-12.10also truncates,%?omits an empty field with its padding, and a character after the width (:in%-12:c) is added after a non-empty value. The leaders arescheduled_leaders,deadline_leaders,timerange_leadersandinactive_leader. A time of day in the headline ("Call Bob 10:00", "8pm") is used when the timestamp has none (search_headline_for_time) and removed from the text (remove_times_when_in_prefix, true or "beg"). Times:time_leading_zero,timegrid_use_ampm,default_appointment_duration(minutes). The grid separator (time_grid.separator) follows the time of timed entries without an end. Tags show inherited tags first, then "::" and the entry's own tags (":ft::work:");hide_tags_regexp(a Vim regexp) hides some,remove_tagsremoves them (true, or "prefix" when %T is used),tags_columnplaces them ("auto" = right edge of the window, 0 = one space after the entry text);ui.todo_keyword_facesandui.tag_facesapply here too. In the clock report, links show as their description. Day headers useformat_date(a strftime format or a function) and show the ISO week on Mondays;weekend_days(0 = Sunday) get the weekend highlight, andday_face_function(date)may return another highlight group (org-agenda-day-face-function).todo_keyword_format("%-1s"; "%-12s" aligns the keywords, "" hides them) formats the TODO keyword (org-agenda-todo-keyword-format).fontify_priorities(org-agenda-fontify-priorities): "cookies" (default) highlights the cookie, the highest priority bold (OrgAgendaPriorityHighest) and the lowest italic (OrgAgendaPriorityLowest), or withui.priority_faces; true does so from the cookie to the end of the line; a table{ A = face, ... }(faces as inui.priority_faces) sets the faces; false turns it off.deadline_faces(org-agenda-deadline-faces) picks the highlight of a deadline line by the part of its warning period that has passed:{ { 1.0, "OrgAgendaDeadline" }, { 0.5, "OrgAgendaDeadlineUpcoming" }, { 0.0, "OrgAgendaDeadlineDistant" } }.remove_timeranges_from_blocksremoves a<...>--<...>range from the headline text of its entries (org-agenda-remove-timeranges-from-blocks).
Sorting
agenda.sorting(org-agenda-sorting-strategy) per view: agenda { "habit-down", "time-up", "urgency-down", "category-keep" } todo, tags { "urgency-down", "category-keep" } search { "category-keep" } Strategies: time-, urgency-, priority-, category-, todo-state-, alpha-, habit-, tag-, effort-, stats-, deadline-, scheduled-, timestamp-, ts-, tsia-, user-defined- (each -up or -down), and category-keep. Urgency is Emacs's: 99 + days late + priority for scheduled entries, priority + days overdue (minus days left) for deadlines in today's agenda, the priority for other entries (A = 2000, B = 1000, C = 0 with the default range) and org-habit-get-urgency for habits. "user-defined-*" callagenda.cmp_user_defined(a, b), which returns -1, 1 or nil. An unknown strategy is an error.sort_notime_is_lateandsort_noeffort_is_highplace entries without a time or an effort.
Agenda keys
All configurable undermappings.agenda: f / b / . later / earlier / today vd vw vt vm vy day / week / fortnight / month / year view (the span starts at the day, week, month or year at point) v<Space> reset the span to the default gd go to a date (Emacs j) c calendar: pick a date and go there gC M S H the date at point in other calendars / phases of the moon / sunrise and sunset / holidays (org-agenda-calendar-keys; Emacs C M S H) r rebuild the view; with a count N in a TODO list, the Nth keyword of the hint line (a count past the last one = ALL); with a count in a tags or search view, edit the query (Emacs C-u r) gr rebuild all agenda buffers (Emacs g) <CR> <Tab> open the entry here / in another window <Space> <BS> show the entry (its drawers open; with a count they stay folded), keeping focus in the agenda; <Space> again scrolls that window a page forward, <BS> a page back (org-agenda-show-and-scroll-up / -show-scroll-down). An agenda key that starts a global mapping or is your leader (<Space>, \ or , as 'mapleader' or 'maplocalleader') waits 'timeoutlen' so the longer keys still work cycle_show (no default key) show the entry; again right away, cycle it through children, subtree, folded; a count is the level ofshow_1(org-agenda-cycle-show) show_1 (no default key) show the entry with the detail of the count: 1 the entry, 2 its children, 3 its subtree, 4 also the drawers (org-agenda-show-1; level 0, fold, has no count form:require("org.agenda.view").show_1(0)) <MiddleMouse> go to the entry clicked (org-agenda-goto-mouse); withagenda.mouse_1_follows_linkalso a short <LeftMouse> click without a drag (a longer one only moves the cursor; the limit islinks.mouse_1_follows_linkms when that is a number, else 450) <RightMouse> show the entry clicked (org-agenda-show-mouse) <C-c><C-x>b edit the entry's subtree in the other window (the subtree edit buffer of org-narrow, since Neovim has no indirect buffers; org-agenda-tree-to-indirect-buffer). The previous one is closed unless modified. A count N takes the subtree of the ancestor at level N.agenda.follow_indirectmakes follow mode show it L show the entry and recenter its window o close the other windows F follow mode (also vf) n / p next / previous item <C-c><C-n/p> next / previous date line <C-Down/Up> next / previous block <M-Down/Up> move the line down / up (the agenda text only) t change TODO state; <C-S-Right/Left> cycle it todo_yesterday (no default key) like t, but the change is logged at 23:59 of yesterday (org-agenda-todo-yesterday) , + - set / raise / lower priority (also <S-Up/Down>) : / T set tags / show tags <C-c><C-x>p set a property s / d schedule / deadline <S-Right/Left> move the date of the entry +1 / -1 day (a count moves more): the timestamp the line comes from; one step on a past date moves it to today (agenda.move_date_from_past_immediately_to_today). A count of 4 (C-u) moves the time one hour, 16 (C-u C-u) onetime_stamp_rounding_minutesstep; the keys keep that unit when pressed again without moving the cursor. The actionsdate_later_hours,date_earlier_hours,date_later_minutesanddate_earlier_minutes(no default keys) take a count > prompt for a new date for that timestamp (the time is kept) e set effort I O X J clock in / out / cancel / go to clocked entry ; start a countdown timer; <C-c><C-x>_ stops the timer R refile $ archive (also <C-c>$, <C-c><C-x><C-s>) a archive witharchive_default_commandafter confirmation ("archive_subtree", "archive_to_sibling", "set_tag" or a function; org-archive-default- command); <C-c><C-x><C-a> without confirmation <C-c><C-x>A move to the Archive sibling <C-c><C-x>a toggle the ARCHIVE tag <C-c><C-a> attach (org-attach on the entry) <C-k> delete the entry in its file (asks when it is longer thanagenda.confirm_killlines) <C-c><C-o> open a link of the entry (choose when there are several) z add a note K capture, with the date at point as default date (Emacs k) A append another view to this one l log mode: closed items and clocks (also vl); 1l also shows state changes, 2l only log items; vL all log items C clock report mode (also vR): a clock table of the agenda files for the shown days (agenda.clockreport_parameters) vc clock check: only clocked entries, with their issues (gaps, overlaps, too long / short, no end time;agenda.clock_consistency_checks) E entry text mode: show the first body lines of each entry (agenda.entry_text_maxlines; a count N shows N lines) (also vE), afterentry_text_leaders, without drawers, planning and CLOCK lines and the matches ofentry_text_exclude_regexps(Emacs regexps) vG toggle the time grid (Emacs G, kept free for motion) ! show / hide deadlines (also v!) D include / leave out the Emacs diary file (org-agenda-diary-file) i add a diary entry for the date at point (org-agenda-diary-entry). Withagenda.diary_entry_file= "diary-file" (default, org-agenda-diary-file) a line of the Emacs diary file (agenda.diary_file) is started, like the calendar's i commands: [d]ay [w]eekly [m]onthly [y]early [a]nniversary [b]lock [c]yclic, incalendar_date_style; a count makes it non-marking ("&"); type the text there. With an Org file: [d]ay (a headline with the date, placed byinsert_diary_strategy: "date-tree", "date-tree-last" or "top-level";insert_diary_extract_timemoves a leading "10:30-11:00" into the timestamp), [a]nniversary (an org-anniversary line under "* Anniversaries"), [b]lock, [j]ump to the date tree. A block spans the days at both ends of a Visual selection (Emacs: point and mark) vh turn habits off / on (agenda.habits.show_habits); with a count, toggle whether today shows every habit, due or not (habits.show_all_today) (org-habit-toggle-display-in-agenda, Emacs K / C-u K); the actiontoggle_habits(no default key) never takes the count # toggle dimming of blocked TODOs (agenda.dim_blocked_tasks: true, false or "invisible"; needsenforce_todo_dependenciesorenforce_todo_checkbox_dependencies) va / vA include archived trees / also the archive files (agenda.start_with_archives_mode: "trees" or true turns them on in new agendas) v[ include inactive timestamps ([leader) / \ < = _ ^ | filters (org-agenda-filter) ~ limit the number of entries (org-agenda-limits) [ ] { } search view: add a +word / -word / +{regexp} / -{regexp} term, the new query also going to registero(agenda.query_register, org-agenda-query-register) (tags views: a +tag / -tag term); date agenda: include inactive timestamps m u U mark / unmark / unmark all <M-m> * <M-*> toggle mark / mark all / toggle all marks % mark entries matching a regexp B bulk action (org-agenda-bulk) <C-c><C-x><C-c> column view (org-agenda-columns) <C-x><C-s> save all modified org buffers <C-_> <C-/> <C-x>u undo the last edit made from the agenda in its file and rebuild the view; again for the edit before (org-agenda-undo).rforgets the edits, like Emacs; an edit is only undone while its file has not changed since (Emacs undoes the file's last change regardless), and an undone edit is dropped (a later undo that is not a repetition does not redo it) <C-x><C-w> write the agenda to a file (org-agenda-export) q quit Q quit and delete the agenda buffer x quit, delete the agenda buffers and the unmodified buffers the agenda loaded A file the agenda (or refile, capture, the clock, ...) loads to make an edit stays out of the buffer list (unlisted-buffer), so it doesn't show up in:lsor a buffer tabline; it's listed once you open it in a window.:wallstill saves it and:qallstill warns about unsaved changes. g? help ? show the MobileOrg flagging note of the entry; again to remove the FLAGGED tag and the note (org-mobile) <C-c><C-x><CR>g / <C-c><C-x><CR>p MobileOrg pull / push Emacs-style aliases: <C-c><C-t> todo, <C-c><C-q> and <C-c><C-c> tags, <C-c>, priority, <C-c><C-x>e effort, <C-c><C-z> note, <C-c><C-x><C-i> <C-c><C-x><C-o> <C-c><C-x><C-x> <C-c><C-x><C-j> clock in / out / cancel / goto, <C-c><C-x><Right/Left> date later / earlier. A count stands for Emacs's prefix argument: 1 = C-u, 2 = C-u C-u, 3 = C-u C-u C-u.
In Visual mode, schedule, deadline, >, the TODO state, the archive commands, <C-k>, set property and set effort act on every entry of the selection (org-agenda-loop-over-headlines-in-active-region: agenda.loop_over_headlines_in_active_region true, false, "start-level" or an Emacs regexp the lines must match). The one-letter keys that are Visual motions (t, $, e, a) keep their Vim meaning there; use their <C-c> forms.
Like Emacs, edits made from the agenda leave the source buffers modified (agenda.save_after_edit = false); save them with <C-x><C-s> or :wall. Buffers are listed, so :qa asks before losing changes. Set save_after_edit = true to write them after every edit.
Like Emacs (org-agenda-change-all-lines), changing the TODO state, the priority, tags, effort or a property, adding a note and clocking in or out re-format only the lines of that entry, in place: a DONE entry stays in the TODO list until the next r, and a line the filters now hide is removed. A repeating entry marked done on today's line shows DONE there. Date changes (S-Right, S-Left, >, schedule, deadline) show the new date at the right edge of the line, " => <date>" (" S => " / " D => " for schedule and deadline, highlight OrgAgendaNewTime), and the entry moves at the next r (org-agenda-show-new-time). Refile, archive, kill, bulk actions and the entry-text mode (E) rebuild the view.
Options: agenda.start_with_log_mode (true, "all" or "clockcheck"), start_with_follow_mode, start_with_clockreport_mode, start_with_entry_text_mode, show_outline_path (echo the outline path of the entry at point).
User autocmds (the Emacs hooks): OrgAgendaFinalize after the agenda buffer is built or rebuilt (org-agenda-finalize-hook), OrgAgendaFilter after a filter changed (org-agenda-filter-hook), with data.buf, data.filters and data.filter (the filter text of the window bar); OrgAgendaBeforeWrite before a written agenda (org-agenda-export). OrgAgendaFinalize also fires after the lines of an edited entry were re-formatted, with data.lines (the agenda lines that changed), like Emacs runs the hook on each of them.
vim.api.nvim_create_autocmd("User", {
pattern = "OrgAgendaFinalize",
callback = function(ev) vim.bo[ev.data.buf].textwidth = 0 end,
})
Windows and buffers
agenda.window (org-agenda-window-setup): "split" (default, Emacs reorganize-frame: the current window and the agenda below it), "only" (only-window), "other" (other-window), "current", "vsplit", "tab" (other-tab), "float". The "split" window fits its lines, between window_frame_fractions ({ 0.5, 0.75 } of the editor height, org-agenda-window-frame-fractions; { 1.0, 1.0 } = the only window). restore_windows_after_quit restores the previous window layout on q. With agenda.sticky (org-agenda-sticky, * in the dispatcher) every command has its own buffer (org://agenda(KEY)), shown as it is when the command is run again (press r to refresh); toggling it deletes the agenda buffers, like :Org agenda_kill_all_buffers (org-agenda-kill-all-agenda-buffers).
Filtering
Filters hide lines without rebuilding the view; they show in the window bar (Emacs shows them in the mode line). / org-agenda-filter: a combined filter such as+work-John<0:10-/plot/: +/- a tag or category (tags win), an effort comparison (< means at most, > at least), a /regexp/ (Emacs syntax). An empty answer removes the filters; a leading+(++work) or a count of 2 adds to the current ones; a count of 1 negates the whole filter; a count of 3 runsagenda.auto_exclude_function\ filter by one tag: its selection key (#+TAGS /tags(k)keys), <Tab> to type a tag, <Space> any tag,?untagged,.the tags of the entry at point,-/+exclude / include the next tag, <CR>auto_exclude_function,\removes the tag filter. Withgroup_tagson, a group tag (#+TAGS: [ Work : Lab ], org-tag-groups) keeps the entries with the group tag or any of its members, recursively (-Workhides them all); <Tab> and/offer the group tags too (org-agenda-filter-expand-tags) < keep the category of the entry at point (again to clear); with a count, hide that category = keep entries matching an Emacs regexp; with a count 1, hide them; again to clear _ effort:<,>or=, then a digit selecting a value ofglobal_properties.Effort_ALL(default "0 0:10 0:30 1:00 2:00 3:00 4:00 5:00 6:00 7:00");_again clears. Entries without an effort count as infinitely long (sort_noeffort_is_high) ^ keep the entries under the top headline of the entry at point | remove all filtersagenda.auto_exclude_function(tag)returns "+tag", "-tag" or nil (org-agenda-auto-exclude-function). Custom commands may preset filters that stay on:tag_filter_preset,category_filter_preset,regexp_filter_preset,effort_filter_preset(lists like { "+work" }).agenda.persistent_filterkeeps the filters when another agenda is built.
Limits
agenda.max_entries, max_todos, max_tags and max_effort (minutes) limit each day or list, as a number or per view type ({ agenda = 5, todo = 10 }); a negative number keeps the entries without the property. ~ sets one interactively (e entries, t TODOs, T tags, E effort); with a count it removes them. Like Emacs, lines without the property (time grid lines too) are dropped while a limit is on.
Bulk actions
B acts on the marked entries, or on the entry at point without marks (org-agenda-bulk-action): $ archive A archive to the Archive sibling t TODO state + / - add / remove a tag r refile s / d (re)schedule / set the deadline: a date, or++2dto shift each entry's own date; an empty answer opens the calendar S scatter: schedule each entry on a random day of the next N days (with a count, weekend days are skipped) f apply a Lua function (function(target, item) ... end) (marked lines showagenda.bulk_mark_char, ">", org-agenda-bulk-mark-char) p toggle persistent marks (agenda.persistent_marks: keep the marks after the action), then choose the action custom keys ofagenda.bulk_custom_functions: { x = { fn = function(target, item, ...) end, desc = "...", args = function() return { ... } end } }
Column view
<C-c><C-x><C-c> in the agenda shows each entry as columns, like column view in an org buffer. The format is agenda.overriding_columns_format, else the COLUMNS property or #+COLUMNS of the entry at point (or of the first entry), else columns_default_format. Date lines and block headers show the summaries of the entries below them (agenda.columns_show_summaries); with agenda.columns_add_appointments_to_effort_sum, an appointment without an effort counts its duration (org-agenda-columns-add-appointments-to- effort-sum). While it is on: q turns it off, e edits the value under the cursor, n/p (<S-Right>/<S-Left>) switch to the next/previous allowed value, v shows the full value. The column titles are in the window's winbar (Emacs header-line). Other agenda commands keep working on the entry at point. agenda.view_columns_initially turns it on for every new agenda.
Exporting agenda views
<C-x><C-w> in the agenda, or:Org agenda export FILE, writes the current view (org-agenda-write). The extension picks the format: .txt the agenda text .html .htm the agenda with its colours, as a <pre> block .org the subtrees of the entries in the view, as level-1 trees .ics iCalendar: an event per timestamp (deadlines of non-TODO entries too), a VTODO per TODO entry .ps .pdf the agenda printed like Emacs's ps-print: Courier text with the highlight colours and bold/italic, paged, with a header box ("Agenda View", page n/m and the date) on every page The text of entry text mode (E) is not written, like Emacs's overlays;agenda.add_entry_text_maxlines(org-agenda-add-entry-text-maxlines, default 0) adds that many body lines under each entry (" > ...").agenda.before_write_hook(lines, path)can then change the lines (or return new ones) and the User autocmdOrgAgendaBeforeWritefires (org-agenda-before-write-hook); when the lines change, HTML and PostScript lose their colours.agenda.export_html_stylereplaces the <style> section of HTML files (org-agenda-export-html-style).
PostScript and PDF are written by Neovim itself, no external program is needed. The layout is ps-print's (letter paper, 8.5 pt text, 72 lines of 97 columns per page; long lines wrap), so pages break where Emacs breaks them. Characters outside Latin-1 are replaced (box drawing by -/|/+, typographic dashes and quotes by ASCII ones, others by ?).
agenda.exporter_settings (org-agenda-exporter-settings) applies when views are written: ps-print variables (- may be written _) set up the printout, other keys are agenda options for the views that org-store-agenda-views builds. A custom command's settings may hold ps-print variables for its own files.
agenda = {
exporter_settings = {
ps_paper_type = "a4", -- letter legal a3 a4small b4 b5 ...
ps_landscape_mode = false,
ps_number_of_columns = 1, -- columns per sheet
ps_font_size = { 7, 8.5 }, -- { landscape, portrait } or a number
ps_print_header = true, -- the header box
ps_print_header_frame = true,
ps_print_color_p = true, -- false/"black-white": no colours
ps2pdf = false, -- make .pdf with ps2pdf, like Emacs
},
}
Also: ps_header_font_size, ps_header_title_font_size, ps_header_lines, ps_left_header and ps_right_header (lists of strings or functions (page, pages)), ps_show_n_of_n, and the margins ps_left_margin, ps_right_margin, ps_top_margin, ps_bottom_margin, ps_header_offset and ps_inter_column (points). With ps2pdf = true and ps2pdf installed, the .pdf is made from the PostScript by ps2pdf, as in Emacs.
Custom commands withexport_files = { "~/today.html", "~/today.txt" }are written all at once byein the dispatcher or:Org agenda e(org-store-agenda-views). From the shell (org-batch-agenda and org-batch-agenda-csv): nvim --headless -c "lua require('org.agenda.export').batch('a', { span = 'day' })" -c q nvim --headless -c "lua require('org.agenda.export').batch_csv('t')" -c q The first argument is a custom command key, a dispatcher key, or a match string; the second one sets agenda options for the run. CSV records have Emacs's fields: category,head,type,todo,tags,date,time,extra,priority-l, priority-n,agenda-day.
Custom commands
agenda = {
custom_commands = {
w = {
description = "Work overview",
types = {
{ type = "agenda", span = "day", header = "Today" },
{ type = "tags_todo", match = "+work/!", header = "Work" },
{ type = "todo", match = "WAITING" },
},
settings = { prefix_format = " %-12:c %s" },
export_files = { "~/work.html" },
},
u = { description = "Urgent", type = "tags", match = "+urgent" },
p = { description = "Projects", type = "tags-tree",
match = "project" },
},
}
Block types:agenda,todo,tags,tags_todo,search,stuck.tags-tree,todo-treeandoccur-treemake a sparse tree of the current org buffer instead (tags match, TODO keyword, Emacs regexp); they cannot be blocks of a composite command. A composite command (types/blocks) shows its blocks one after the other, separated by a blank line andagenda.block_separator(none withcompact_blocks, which also drops the date agenda header).settings(Emacs's options list) applies to every block unless the block sets the option itself. Block options: match match string (see org-match-syntax), TODO keywords fortodo, or text forsearchheader heading shown above the block; "" for none; a function returning it (alsoorg_agenda_overriding_header) span span foragendablocks start_day first day foragendablocks files files to use instead ofagenda_filesskip function(headline) that returns true to skip an entry (alsoorg_agenda_skip_function). Helpers like Emacs' org-agenda-skip-entry-if / -subtree-if: local agenda = require("org.agenda") skip = agenda.skip_entry_if("scheduled", "deadline") skip = agenda.skip_subtree_if("regexp", ":someday:") Conditions: scheduled, notscheduled, deadline, notdeadline, timestamp, nottimestamp, regexp RE, notregexp RE, todo KWS, nottodo KWS (KWS: a list of keywords, or "todo", "done", "any") sorting sorting strategies of this block *_filter_preset filters that stay on (org-agenda-filter) any otheragendaoption (prefix_format,entry_types,todo_ignore_*,show_future_repeats,max_entries, ...), also with Emacs names:org_agenda_entry_types,org_agenda_prefix_format, ... Keys may be several characters long; a string entry (w = "Work") only labels the group.
agenda.custom_commands_contexts (org-agenda-custom-commands-contexts) offers commands only in some buffers, with the rules of org-capture-contexts: { "p", { { in_mode = "org" } } } keeps p only in org buffers, { "p", "r", { rules } } runs the command of r under p where a rule holds (and hides r). It applies to the dispatcher, :Org agenda KEY and A.
TODO lists: todo_ignore_scheduled ("all", "future", "past" or days), todo_ignore_deadlines (true = "near": within the warning period, "far", "all", "future", "past" or days), todo_ignore_timestamp, todo_ignore_with_date hide dated entries (org-agenda-todo-ignore-*; they compare dates in days, or with the current time in seconds with todo_ignore_time_comparison_use_seconds); tags-todo (M) views honour them only with tags_todo_honor_ignore_options. todo_list_sublevels = false skips the children of a listed TODO; tags_match_list_sublevels = false those of a match.
Stuck projects
agenda.stuck_projects (org-stuck-projects): projects matching match ("+LEVEL=2/-DONE") are stuck unless a heading of their subtree, the project heading included, has one of todo_keywords ({ "TODO", "NEXT", "NEXTACTION" }; "*" = any not-done keyword) or tags ("*" = any tag), or the subtree text matches the Vim regexp text.
Search view
A plain query is a phrase whose spaces match any whitespace, newlines
included ("banana split" finds "banana\n split"). A query starting with
+, - or { is boolean: +word must and -word must not occur, "a
phrase" in double quotes counts as one word, {regexp} is an Emacs
regexp, and word\ word joins two words. A leading * searches
headlines only, ! TODO entries only, : makes words match whole words.
Matching ignores case.
agenda.search_view_always_boolean treat every query as boolean
agenda.search_view_force_full_words words match whole words only
agenda.search_view_max_outline_level entries below this level are
searched as part of their ancestor
(0 = no limit)
agenda.text_search_extra_files more files to search; include
"agenda-archives" for the archive
files
Diary sexp entries
Emacs lets you put diary s-expressions in timestamps, <%%(diary-float t 4 2)>, and on lines of their own at the start of a line, %%(org-anniversary 1990 5 17) Birthday of Joe (%d). agenda.diary_sexp_prefix (an Emacs regexp, org-agenda-diary-sexp-prefix) moves its match in the text of a %%(...) line to the leader (%s). Emacs evaluates them as Emacs Lisp. Neovim has no Lisp interpreter, so they are read with a small, safe s-expression reader and the common calendar functions are emulated, with the same results as Emacs:
org-anniversary Y M D diary-anniversary M D [Y] org-cyclic N Y M D diary-cyclic N M D Y org-block Y1 M1 D1 Y2 M2 D2 diary-block M1 D1 Y1 M2 D2 Y2 org-date Y M D diary-date M D Y diary-float MONTH DAYNAME N [DAY] org-class Y1 M1 D1 Y2 M2 D2 DAYNAME [ISO-WEEKS...] diary-remind SEXP DAYS [MARKING] diary-offset SEXP DAYS diary-hebrew-date diary-islamic-date diary-bahai-date diary-chinese-date diary-julian-date diary-iso-date diary-astro-day-number diary-french-date diary-mayan-date diary-coptic-date diary-ethiopic-date diary-persian-date diary-day-of-year diary-lunar-phases diary-sunrise-sunset diary-hebrew-birthday M D Y [AFTER-SUNSET] diary-hebrew-yahrzeit M D Y [MARK AFTER-SUNSET] diary-hebrew-omer diary-hebrew-parasha diary-hebrew-rosh-hodesh diary-hebrew-sabbath-candles diary-chinese-anniversary M D [Y] and or not list quote
Sexps can also combine these with a side-effect-free subset of Emacs Lisp, evaluated like Emacs with date bound to (MONTH DAY YEAR) and entry to the text after the sexp:
if when unless cond let let* progn = /= < > <= >= eq eql equal memq memql member null not zerop + - * / % mod 1+ 1- abs max min car cdr cadr nth length concat format number-to-string string= integerp numberp stringp calendar-day-of-week calendar-extract-month/-day/-year calendar-absolute-from-gregorian calendar-gregorian-from-absolute calendar-iso-from-absolute calendar-nth-named-day calendar-last-day-of-month calendar-leap-year-p calendar-day-number
* Gym
%%(when (memq (calendar-day-of-week date) '(1 2 4 5)) "18:00 Gym")
* Payday
%%(= 0 (mod (- (calendar-absolute-from-gregorian date) (calendar-absolute-from-gregorian '(9 4 2026))) 14))
A string result replaces the entry text (the first example shows "18:00 Gym" at 18:00), a list of strings gives one line each, and any other non-nil value shows the text after the sexp. There are no loops, lambda or assignments, so every sexp finishes and changes nothing.
A sexp beyond this subset (other Lisp functions, cl-*, ...) is evaluated in a separate emacs --batch when there is one (babel.emacs_lisp), like org-diary-sexp-entry: (let ((entry ENTRY) (date '(M D Y))) SEXP) with Org and diary-lib loaded. One Emacs runs per sexp and agenda span (all the days at once, under half a second), and the results are kept for the session. Without Emacs the entry is skipped with a message.
The diary-* functions take their arguments in the order of agenda.calendar_date_style (calendar-date-style): "american" (month day year, the default), "european" (day month year) or "iso" (year month day). The org-* variants always use ISO order (year month day). In diary-date/org-date, t matches any value and a list '(1 2) matches any of its elements. In diary-float, MONTH may be t or a list, DAYNAME is 0 (Sunday) to 6, and a negative N counts from the end of the month. The entry text of anniversaries and cycles may contain %d (years or repetitions) and %s (its ordinal suffix, "st", "nd", ...); a result with "; " gives several agenda lines.
diary-remind shows the entry of a quoted SEXP on its day and "Reminder: Only N days until ENTRY" DAYS days before ("2 weeks" for whole weeks; DAYS may be a list, or -N for 1 to N days); MARKING only matters for the Emacs calendar and is ignored. diary-offset shows SEXP's entry DAYS days later (earlier when negative):
* Taxes
%%(diary-remind '(diary-date 4 15 t) -7) File the taxes
* Retro
%%(diary-offset '(diary-float t 4 -1) 1) Retro, the day after
The diary-*-date functions show the day in another calendar, e.g. "Hebrew date (until sunset): Tishri 16, 5787", like Emacs (in the date form of agenda.calendar_date_style: "16 Tishri 5787" in european style, "5787-07-16" in iso style). diary-lunar-phases shows the phases of the moon and diary-sunrise-sunset sunrise and sunset at agenda.calendar_latitude and agenda.calendar_longitude (org-agenda-calendar-keys; without them the sexp is skipped with a message), in the system time zone.
The entries of the Hebrew calendar are Emacs's (cal-hebrew.el): diary-hebrew-birthday ("Joe's 13th Hebrew birthday", and " (evening)" the day before; the entry text is the name) and diary-hebrew-yahrzeit ("Yahrzeit of Joe: 5th anniversary") take the civil date of birth or death, the day after with AFTER-SUNSET; diary-hebrew-omer counts the Omer, diary-hebrew-parasha names the weekly parasha on Saturdays (with the Israel and diaspora readings when they differ), diary-hebrew-rosh-hodesh shows Rosh Hodesh, Erev Rosh Hodesh and Shabbat Mevarchim, and diary-hebrew-sabbath-candles the candle lighting time on Fridays, agenda.hebrew_sabbath_candles_minutes (18) before sunset at the calendar location. diary-chinese-anniversary is diary-anniversary for a date of the Chinese calendar, with the year written CYCLE * 100 + YEAR (7843 for year 43 of cycle 78):
%%(diary-hebrew-yahrzeit 11 25 1990) Grandpa
%%(diary-chinese-anniversary 8 15 7840) Moon cake %d%s
Like Emacs, %%(...) lines are found in the whole file: lines before the first heading give entries with the file's category and FILETAGS. They have no heading, so <Tab>/<CR> jump to the line and commands that change an entry (t, s, :, ...) report "Before first headline". (Org 9.8.10 itself stops the agenda with that error when such a line matches.)
Holidays
A %%(org-calendar-holiday) line shows the day's holidays, like Emacs's calendar-check-holidays: several on one day give several agenda lines.
* Holidays
:PROPERTIES:
:CATEGORY: Holiday
:END:
%%(org-calendar-holiday)
The holidays come from agenda.holidays (calendar-holidays), with the Emacs defaults: one list per holiday-*-holidays variable (general (the United States), local, other, christian, hebrew, islamic, bahai, oriental and solar), and the flags christian_all, hebrew_all, islamic_all, bahai_all and chinese_all (calendar-*-all-holidays-flag, false). Set a group to {} to drop it; list replaces the default. Items are Emacs's holiday forms written as Lua lists, or Lua functions:
agenda = {
holidays = {
general = {}, -- no US holidays
christian = { -- only Christmas and Easter Sunday
{ "holiday-fixed", 12, 25, "Christmas" },
{ "holiday-easter-etc", 0, "Easter Sunday" },
},
["local"] = {
{ "holiday-fixed", 9, 16, "Independence Day" },
{ "holiday-float", 11, 1, 3, "Revolution Day" }, -- 3rd Monday
function(year) -- holiday-sexp: { MONTH, DAY, NAME } per year
return { { 2, 5, "Constitution Day " .. (year - 1917) } }
end,
},
},
}
{ "holiday-fixed", MONTH, DAY, NAME }{ "holiday-float", MONTH, DAYNAME, N, NAME [, DAY] }(the Nth DAYNAME, 0 = Sunday, from DAY; negative N counts backwards){ "holiday-easter-etc" [, N, NAME] },{ "holiday-advent" [, N, NAME] },{ "holiday-greek-orthodox-easter" [, N, NAME] }(N days from Easter, Advent Sunday or Pascha; without arguments the default holidays){ "holiday-julian" | "holiday-hebrew" | "holiday-islamic" | "holiday-bahai" | "holiday-chinese", MONTH, DAY, NAME }(a date of that calendar){ "holiday-hebrew-passover" },-rosh-hashanah,-hanukkah,-tisha-b-av,-misc,{ "holiday-islamic-new-year" },{ "holiday-bahai-new-year" },-ridvan,-twin-holy-birthdays,{ "holiday-chinese-new-year" },-qingming,-winter-solstice,{ "solar-equinoxes-solstices" }and{ "holiday-daylight-saving" }(the Emacs functions of the same names){ "if", FLAG, ITEM... }(the items whenholidays[FLAG]is true)
Equinox, solstice and daylight saving times use the system time zone, like Emacs's calendar-time-zone. A bad item is reported once and skipped. Differences: Emacs evaluates each item as Lisp (holiday-sexp and other Lisp forms become Lua functions here).
Calendar commands
Emacs's calendar commands on the date at point of a date agenda (a date line or an item of that day):
gC the date in other calendars (org-agenda-convert-date, Emacs C):
Gregorian, ISO week, day of the year, Julian, astronomical day
number, Hebrew, Islamic, French Revolutionary, Bahá’í, Mayan,
Coptic, Ethiopic, Persian and Chinese
M the phases of the moon in the three months around the date, with
possible eclipses (org-agenda-phases-of-moon)
S sunrise, sunset and hours of daylight on the date
(org-agenda-sunrise-sunset); with a count, ask for the location
H the holidays of the three months around the date, from
agenda.holidays (org-agenda-holidays)
gC, M and H show a float (q closes it), S a message. Sunrise and sunset need a location:
agenda = {
calendar_latitude = 40.7, -- calendar-latitude, north positive
calendar_longitude = -74.0, -- calendar-longitude, east positive
calendar_location_name = "New York", -- default "40.7N, 74.0W"
}
When they are unset, S asks for them (Emacs's solar-setup) and keeps the answers for the session. Times use the system time zone and its daylight saving rules, like Emacs's calendar-time-zone. The strings are Emacs's, with the default calendar-date-display-form of agenda.calendar_date_style (american "Sunday, September 27, 2026", european "Sunday, 27 September 2026", iso "2026-09-27"); calendar-date-display-form itself, lunar-phase-names and calendar-time-display-form are not configurable.
The Emacs diary file
With agenda.include_diary (org-agenda-include-diary), or after D in the agenda, each day of a date agenda also lists the entries of the Emacs diary file for that day, with category "Diary", like Emacs:
agenda = {
include_diary = true,
diary_file = "~/.emacs.d/diary", -- default: ~/diary if it exists,
-- else the Emacs user directory's
calendar_date_style = "american", -- "european", "iso"
diary_show_holidays = true, -- diary-show-holidays-flag
diary_include_files = false, -- read #include "FILE" lines
diary_nongregorian = {}, -- "hebrew", "islamic", "bahai",
-- "chinese" (H, I, B, C entries)
}
The file is read the way Emacs's diary-list-entries reads it: an entry starts at the beginning of a line with a date in one of the forms of calendar_date_style (diary-date-forms), followed by its text; indented lines below continue it:
9/27 Weekly review MONTH/DAY
9/27/2026 Dentist 10:30 MONTH/DAY/YEAR (or a two-digit year)
Sep 27 Birthday MONTHNAME DAY (full or three letters,
September 27, 2026 Party with or without a period)
MONTHNAME DAY, YEAR
Tuesday 10am Meeting DAYNAME (full or abbreviated): weekly
* 15 Pay day `*` matches any day, month or year
&10/3 Not marked the `&` (non-marking) prefix
10/4 a date alone: the indented lines are
Trip to Boston the entry
2pm Meeting
%%(diary-float t 4 -1) Last Thursday a sexp entry
European style reads DAY/MONTH, DAY/MONTH/YEAR, DAY MONTHNAME and DAY MONTHNAME YEAR; iso style MONTH/DAY, YEAR-MONTH-DAY (or /), MONTHNAME DAY and YEAR MONTHNAME DAY. The diary %%(...) sexps use the same functions as Org's, evaluated with date and entry bound.
The agenda lines are Emacs's: the day's holidays (agenda.holidays, unless diary_show_holidays is false) come first, then the sexp entries, then the dated entries (one date form after the other), the entries of other calendars and the included files; the lines of an entry are joined with "; " except the lines starting with a time, which become entries of their own. A time at the start of a line ("10:30", "2pm", "8:30-9:15") goes to the time column and the time grid; face attributes such as [foreground:red] are removed. D toggles the diary for the current agenda (org-agenda-toggle-diary); a block of agenda.custom_commands can set include_diary too. <Tab> and <CR> on a diary line jump to the line of the diary file (the last line of the entry, like Emacs); the commands that change an Org entry (t, s, :, ...) report "Command not allowed in this line", as do jumps from a holiday line.
With diary_include_files, #include "FILE" lines (relative to the diary file's directory) add the entries of other diary files, recursively (Emacs: diary-include-other-diary-files in diary-list-entries-hook). With diary_nongregorian, entries prefixed with H, I, B or C are dates of the Hebrew, Islamic, Bahá’í or Chinese calendar, in the same forms with that calendar's month names (not abbreviated): HTishri 16 Sukkot, IRamadan 1 Fast, C8/15 Mid-autumn (diary-nongregorian-listing-hook). Differences: customized diary-date-forms, diary-comment-start, diary-list-include-blanks and diary-face-attrs are not supported, and a missing or recursive include is skipped with a message (Emacs stops with an error).
Not supported in the agenda
- Without an Emacs executable, Emacs Lisp beyond the subset above (loops,
lambda,defun, assignments, other libraries) and theholidaysargument oforg-class: an unsupported sexp is skipped with a message (once per session). With one, they run in a separate Emacs that has none of your session's state (variables, functions you defined;calendar-date-styleis set fromagenda.calendar_date_style) unlessbabel.emacs_lisp.argsloads it. Holidays (org-agenda-holidays) and the entries of other calendars (org-agenda-diary-sexp) are supported. - The Customize keys (
C,!in the dispatcher): there is no Customize. - Keys that differ on purpose, to keep Vim motions:
n/pmove by item (Emacs: by line; N/P by item),jandkare motions (go to date isgd, captureK),gis a Vim prefix (redo all isgr),s/dschedule and set deadlines (Emacs: save and day view; views arevd,vw,vt,vm,vy),Rrefiles (the clock report isC/vR, so the calendar conversion isgC), and habits are toggled withvh(EmacsK, which is capture here).