The Emacs secretary that helps you through all your inboxes and tasks.
el-secretario
is available on melpa and is divided into different packages:
el-secretario
: The main packageel-secretario-org
: Org-mode integrationel-secretario-notmuch
: Notmuch integrationel-secretario-mu4e
: Mu4e integrationel-secretario-elfeed
: Elfeed integrationNote: el-secretario
depends on a newer version of which-key than might be on elpa. See Bug: which-key: No bindings found in el-secretario-org-keymap
No calls to require
(explicit or with use-package
) is needed since all relevant functions are properly autoloaded.
If you are using doom:
(package! el-secretario)
Install manually from MELPA: M-x package-install RET el-secretario RET
Or via use-package
:
(use-package el-secretario
:defer t)
I post announcements about breaking changes on https://lists.sr.ht/~zetagon/el-secretario-announce . If you don’t have an sr.ht account, see https://man.sr.ht/lists.sr.ht/#email-controls for how to subscribe using your email account.
There are at least two fundamental ways of reading email. The first, and the one I think is more common, is to open the inbox and choose an email to read from the list. Let’s call it the random access method. The other method is to open an email, preferably the oldest unread one, and when you are done open the next one by pressing a “next email” button. Let’s call it the linked list method.
This package was born from the realization that I like the linked list method, and that I would like to handle more things this way. So what el secretario does is that he turns different sources (e.g. org-mode todo items or RSS feeds) into linked list-style inboxes. And he doesn’t stop there, he can also link different lists together so that email, org-mode items and RSS feeds come under the same unified inbox. El secretario can already turn many different things into inboxes but he can also learn new things if you teach him.
This was all very abstract so let’s move on to a concrete example:
;; Create a function to start the review
(defun el-secretario-daily-review ()
(interactive)
(el-secretario-start-session
(lambda ()
(list
;; First take care of email
(el-secretario-notmuch-make-source "tag:lists/emacs-orgmode")
;; Then Take care of inbox
(el-secretario-org-make-source nil ("~/org/Inbox.org"))
;; Go through TODOs
(el-secretario-org-make-source '(todo "TODO") '("~/org/Todo.org"))))))
Above is a sample configuration, and here is a gif where its used in action.
Calling el-secretario-daily-review
will open up your oldest email. Pressing
n
in the which-key prompt will take you to the next email sorted chronologically.
In this way your secretary will make sure you go through all your email without
having to worry about which or how many emails you will read.
Then when your secretary has gone through all your email for you, they will next
go through your todo inbox. Pressing n
will in a similar way take you to the
next item in your inbox. When you’ve refiled your tasks appropriately your
secretary will go through all your existing todos over in Todo.org
Pressing a key that isn’t in the which-key
menu will disable the menu, which
essentially pauses the review. You can reactivate it with
el-secretario-activate-keymap
.
A more complete configuration can be found at my configuration.
The fundamental building block. Items are the thing that you review from each source, for example an email or a todo.
A session consists of a list of sources. Each source consists of a list of items.
The example above has one notmuch source, and two org sources.
el-secretario
comes with a set of modules that will help you with reviewing
various parts of your system.
In general functions and variables that are for users follow the format
el-secretario-MODULE-NAME
and names for developers follow the format
el-secretario-MODULE--NAME
(notice the two dashes).
A very simple module that goes through your email in chronological order. The
relevant function is just el-secretario-notmuch-make-source
, look at its
docstring for more info.
el-secretario-next-item
and el-secretario-previous-item
will go to the next
and previous thread respectively. If you want more granularity I recommend
using el-secretario-notmuch-advance-and-archive
instead of
el-secretario-next-item
which will call notmuch-show-advance-and-archive
,
i.e. scroll through the thread until you are at the end, at which point it will
archive the thread and go to the next thread.
Very similar to the notmuch module. It goes through your mu4e email. The
relevant function is just el-secretario-mu4e-make-source
, look at its
docstring for more info.
Very similar to the notmuch module. It goes through your elfeed items in
chronological order, oldest first. The relevant function is just
el-secretario-elfeed-make-source
, look at its docstring for more info.
A very simple module that goes through your todos. The relevant function is just
el-secretario-org-make-source
, look at its docstring for more info.
El secretario can update tags of headings according to a state machine. The
first time you review an item one state transition is done. The state machine is
defined per source with the TAG-TRANSITIONS
argument to
el-secretario-org-make-source
. It is a list of (TAG . NEW-TAG)
cons pairs.
Each reviewed heading that has the tag TAG
gets the tag TAG
removed and
NEW-TAG
added. If TAG
is the empty string NEW-TAG
is always added.
Example
(el-secretario-org-make-source '(todo)
"~/org/Todo.org"
:tag-transitions
'(("a" . "b")
("b" . "c")
("" . "d")
("d" . "")))
* TODO Foo :a:
* TODO Bar :b:
With the el-secretario source and org file above, one review will result in the org file below. All “a” tags have turned into “b” tags, and all “b” tags have turned into “c” tags. “d” is added to both.
* TODO Foo :b:d:
* TODO Bar :c:d:
A second review will have converted all tags to “c”.
* TODO Foo :c:
* TODO Bar :c:
This module has some convenience functions:
el-secretario-org-remove-tag
el-secretario-org-up-heading
Property hooks are similar to normal hooks in that they allow the user to run
custom code at specific points in time. The difference is that property hooks
are defined by setting a property to a headline which means that they are local
to the headline. You can set a property hook by adding the corresponding
property with an unquoted lisp function as value. You can run your own property
hooks with the function el-secretario-org--run-property-hook
.
Property | Run condition |
---|---|
EL-SECRETARIO-REVIEW-TASK-HOOK | When shown in a review in the org source |
Example:
This will call the function review-item-fun
when the Foo entry is shown in a review:
* Foo
:PROPERTIES:
:EL-SECRETARIO-REVIEW-TASK-HOOK: review-item-fun
:END:
In order to run a function when a specific task is done, you can add the following to your config.
(add-hook 'org-after-todo-state-change-hook #'el-secretario-tasks--finish-task-hook)
(defun my/el-secretario-run-finish-task-hook ()
(when (member org-state org-done-keywords)
(el-secretario-org--run-property-hook (el-secretario-org--parse-headline)
:EL-SECRETARIO-FINISH-TASK-HOOK)))
A spaced repetition module for tasks (and not memorization!). When you begin to
have lots of todos it becomes very tiring to review all of them all the time.
This module provides a way to defer todos into the future using a crude spaced
repetition algorithm (the length of the deferral is incremented by one day each
time). Note that it uses org-mode’s SCHEDULE
property so it will mess with
items you have scheduled.
Currently this module doesn’t stand on it’s own and serves more as a library that augments the org module. See my config for an example of how to use it.
el-secretario-org-space-increment-percentage
el-secretario-org-space-reschedule
el-secretario-org-space-schedule-and-reset
el-secretario-org-space-compare-le
Passing this function as a comparison function to make-el-secretario-source
will ensure that you review your items sorted so that the earliest scheduled
items comes first. This can be useful to create a queue of tasks that are
roughly sorted by how relevant they are.
A simple module that goes through a list of files in order.
el-secretario-files-make-source
is the entry point.
Visit all your downloaded files:
(el-secretario-start-session
(el-secretario-files-make-source (directory-files "~/Downloads")))
An extremely simple source for when you want a function to be called
automatically during a specific time in the review. It calls the provided
function each time the source is activated and goes to the next source
immediately when el-secretario-next-item
is called. To use it put
(el-secretario-function-source :func #'YOUR-FUNCTION)
in your source list.
It’s easy to add your own keybindings! Use whatever keybinding mechanism you use to add keybindings the respective source’s keymap.
For example to bind org-capture
in the org keymap:
(define-key el-secretario-org-keymap
"c" '("Capture" . org-capture))
If you want different keybindings for different instances of the same source type you can provide your own keymap. The example below has two different keymaps for the two sources.
(defvar my/el-secretario-org-map (make-sparse-keymap))
(define-key my/el-secretario-org-keymap
"c" '("Capture with template a" . (lambda () (interactive) (org-capture nil "a"))))
(defvar my/el-secretario-org-map-2 (make-sparse-keymap))
(define-key my/el-secretario-org-keymap
"c" '("Capture with template b" . (lambda () (interactive) (org-capture nil "b"))))
(defun el-secretario-review ()
(el-secretario-start-session
(lambda ()
(list
(el-secretario-org-make-source '(todo "TODO") '("~/org/Todo.org")
:keymap my/el-secretario-org-map)
(el-secretario-org-make-source '(todo "TODO") '("~/org/Inbox.org")
:keymap my/el-secretario-org-map-2)))))
Doom’s map!
macro doesn’t play well with el-secretario
and which-key
. It
will cause some descriptions for keybindings to be overwritten. Instead I
recommend using define-key
as shown above.
A source is a eieio class that inherits from el-secretario-source
. It needs to
implement the following methods:
el-secretario-source-next-item
el-secretario-source-previous-item
el-secretario-source-activate
Optionally el-secretario-source-init
can be implemented if your source needs
to do some setup only once (e.g. setup some state).
See the docstrings for respective method for what they are supposed to do.
Each source can fill the keymap
slot (as defined in el-secretario-source
)
with a keymap. Otherwise the default keymap will be used.
See the example source and its unit tests for an easy to read example.
el-secretario
is mostly a glue-package and it couldn’t exist without all the
fantastic things it glues together! Huge thanks to the creators of:
There are three ways to contribute to this project:
Feedback
Any feedback is very welcome! Documentation, usability, features etc.
Patches
el-secretario
is designed to be extensible. Write your own sources and
contribute them, or improve the existing ones.
Money
I have a ko-fi page if you want to throw money at me: https://ko-fi.com/zetagon
It would be very nice to have a mascot for the project, so I would be very happy if you would contribute with a nice drawing.