How I mapped my brain to org-mode
Lately I found that I am in dire need of an effective task management system as an IT support. There are some days where everything is hectic and I’m lost prioritizing my assignments. There’s moment where I was in the middle of doing one task, and suddenly another request / assignment came out of nowhere (not exactly nowhere, but you get the idea). Task management system is also useful for creating some kind of reporting, although this is not the main goal.
Initially, this post was titled Getting Things Done in Emacs. But as I keep adding more information into this post, and how I interact with org-mode and Emacs in general, it was about capturing my thought process. Tasks is one thing, and the important one since that’s what I’m paid for. But there are stuffs floating around in my brain that I want to keep on exploring. By storing all that impulses into text, hopefully I could understand more on how my thought process work.
I’ve known about the Getting Things Done method for a while now, even though I don’t actively trying to mimic the workflow. subconsciously I created my own workflow that (more and less) similar.
The more I try to update this post the more I realised that my mind operates in such a non-linear way. I was thinking of updating a section of this post, but suddenly an idea came into my mind about tweaking other sections of the post, I don’t know if this is a good thing or not…
I promise one day this post will make sense (to me most especially).
Basically what I want is
- daily planner.
- Simple UI for task highlighting or focusing.
- automation or templating for capturing tasks.
- reviewing
- Sync between Laptop, PC, and android
The 5 Steps from David Allen’s GTD Method
- Capture
- Empty your mind
- Clarify
- Describe
- Organize
- Place it where it belongs
- Reflect
- Reflect on your progress
- Engage
- Take action
Capture
Our minds are for having ideas, not for holding them.
Each capture should produce just one headline. Try not to use the word and and or into a headline. Put a line below write every thing that’s on my head at the time of capturing process.
- Dumping every ideas into text should be avoided. Not everything should go into the system, only add what I really need.
- Separate each capture into categories, tasks, notes, ideas, or other information that I took interest of.
- Since it’s necessary to me, I also separate my personal tasks/notes/ideas using tag.
This is the first step of my workflow, and this is not necessarily about Emacs. I try to capture everything that interest me, or things that need my attention.
- A request came via E-mail, messaging apps, phone calls, or in person.
- An interesting book about meditation that requires a dedicated time to read.
- A topic about GNU/Linux from a debian mailing list (yes, silent reader here, but I still read it).
As it seems, I don’t really need to capture it immediately into my inbox file, though it’s better, as long as I have some kind of media to note them.
- Mail messages have their received date and time.
- So do every messaging apps known to man.
- In-person requests / inquiries time doesn’t have to be precise to the minutes.
Clarify
Create sub tasks if needed. Reading a hierarchy of lists is better than reading a long line of text. Since I made these notes for me, I should understand it just by looking at them. But still every details count, especially product-related information (type, serial numbers, conditions etc).
Another important details are date, time, and location. These are usually tasks related to meetings, appointments and such.
This is also the first step to decide whether a tasks is considered a project. When I encounter tasks that take prolonged time of actions, and would create another task, I put it in the :project:
category.
For every other captures that doesn’t require any actions, I tried to collect as much information as possible. It could be a link to some internet articles that I’ve already collected, but somehow I forgot, it’d be nice if I knew the reason why I capture it in the first place. So the second time I encounter it I can immediately decide if it worth keeping.
Organize
Use org-refile
to organize your inbox file.
A further sorting of all the lists I’ve acquired. Including all that I’ve captured previously. This phase is where I separate my tasks (actionable) with information, notes, links etc (non-actionable).
I usually don’t trash any of my notes, if I made mistakes, it was my mistakes and I can (hopefully) learn from it.
Reflect
A deeper inspection of my org-agenda
view. I should have an agenda view that shows everything happening for the current day, all the tasks that hasn’t yet completed, and all prioritized tasks for the upcoming week. Within the org-agenda
, I can decide what tasks should I do first and mark them in-progress (PROG
), what should I do next (:schedule:
or :deadline:
them if necessary).
I’m still contemplating on having a separate org-agenda
view for weekly. The problem is it really took a mental energy to view them and make decisions about a large inventory of open loops. Ath the moment I only set them for prioritized / scheduled / deadline tasks.
Engage
Take action. Useful questions:
- Context
- is this the right context for this action?
- Priority
- Is this the most important / impactful activity?
- Energy
- Do I have enough energy to do this?
- Time
- Do I have enough time to do this?
What I will need
- Time
- This is basically building a habit, fortunately since I’ve used Emacs for a while now, this is nothing strange to me.
- Keep It Simple
- My Emacs configuration is already bloated enough, also the reason why I use vanilla Emacs to build this system.
References
- https://medium.com/praxis-blog/building-a-second-brain-in-emacs-and-org-mode-faa20ae06fc
- https://fortelabs.com/blog/para/
- https://fortelabs.com/blog/progressive-summarization-a-practical-technique-for-designing-discoverable-notes/
- https://www.float.com/resources/getting-things-done-method/
Using org-mode
An Emacs nerd as I am, of course the first stop is org-mode
. Please forgive this messy chart since I’m still learning on plantuml.
I really want to try from the ground up, using a vanilla Emacs with no interference from my actual configuration file1. First of all, we need to set the minimal keybinding suggested by the manual:
Keybindings
|
|
Specific org-mode
variables
org-directory
and org-agenda-files
Next is set the org-directory
, this directory is going to be the location of org-mode
files, well, you are free to place an org-mode
files anywhere, but think of this as the root location, so every customizations we’ll be making will refers to this location, for example, if we want to define our org-agenda-files
as agenda.org
inside the org-directory
, we’ll use:
|
|
Usually you’ll want your org-directory
to be separated from your user-emacs-directory
, which mostly be under some kind of version control system (such as git). The simplest location is just on the root of your home-directory
|
|
Assuming your user-emacs-directory
is in ~/.emacs.d~
, then your org-directory
is ~/.emacs.d/org
|
|
org-archive-location
org-archive-location
is another variable that I should consider, will I want an archiving method? If I do, where should I put it? Is storing archived task (the done, cancelled etc) in a designated file necessary?
|
|
org-todo-keywords
The org-todo-keywords
also need to be customized, the default keywords are just TODO
, and DONE
. I’ve thought of this for a while, and perhaps this will suffice:
TODO Keyword | What it is |
---|---|
TODO | Tasks that are not started, also not planned. There can be many of them. |
NEXT | Tasks that are planned to do immediately. |
WAIT | Tasks that needs other form of interaction in order for it to be set as PROG or DONE or KILL . |
PROG | Tasks that are actively in working progress, these are usually the kind of tasks that can be done by myself, or have gone through the WAIT phase. Which also means that this can also revert back to WAIT . |
HOLD | The kind of tasks that suspended without an escalation (these things happens im my workplace). |
These TODO
keywords are the ones that (supposed) to have further actions. I only have three keywords with no further actions:
TODO keyword | What it is |
---|---|
DONE | GG, well played! |
DELEGATED | I got someone else doing my job, GG, well played! |
KILL | Cancelled, or my boss gave me a task beyond my paygrade |
Translate these into Emacs Lisp:
|
|
- each character inside the parentheses are the fast state selection, when you use
C-c C-t
in a heading, you only have to type the character to select the keyword. ~~
means to record the time of state changes.1 2
* TODO test - State "TODO" from [2024-03-14 Thu 22:10]
Priority
Prioritizing tasks is important in my daily routines. And I would like to quickly identify the priority of all the tasks I have in my hand.
|
|
This will set a list of priority from A
to D
, the default keybinding is C-c ,
.
Tags
Another useful way to implement labels and contexts for headlines, in org-mode
tags must be preceeded and followed by a single colon (:
), for example :work:
, several tags can be specified, as in :work:urgent
. Although I don’t use tags that often, there are several variables that I should customize:
|
|
The first one should be obvious, I want my sub-level headlines to inherit the tags from their parent headline. the second one is the tag that should not be inherited. The :crypt:
tag is usually used for tagging headlines that contains password etc. The default keybinding for inserting tag is C-c C-c
when the point is in the headline, or C-c C-q
when under a headline.
Deadlines and Schedules
Time-stamp
In org-mode
it’s a timestamp with a special keywords. Adding timestamp can be done with C-c .
inside a heading, to insert an inactive timestamp (that doesn’t show in org-agenda) use C-c !
. This will only insert date, to also insert time, use a C-u
prefix (e.g. C-u C-c .
or C-u C-c !
).
Deadline
The default keybinding is C-c C-d
. Meaning the heading, with a keyword (can be TODO
or any other), is supposed to be finished at that date. Use C-u C- C-d
to remove a deadline from the heading.
|
|
There are also different syntax for the date:
DEADLINE: <2024-03-14 Thu -3d>
means a warning with the period of 3 days,
Schedule
Meaning that I’m planning to start doing the tasks at that date. The default keybinding is C-c C-s
, use C-u C-c C-s
to remove a schedule from a heading.
|
|
Just as deadline, a different syntax also available:
SCHEDULED: <2024-03-16 Sat 10:00 -2d>
means to delay the display of this task in the agenda for 2 day. The task is still scheduled on the 16th.
The Agenda view.
org-mode
has a builtin agenda. The default Agenda views will show informations of:
- Agenda for the current week or day, with the default key
a
. - List of all
TODO
entries, keyt
. - Matching queries of tags, properties, or
TODO
keywords. With the keym
. s
, search for keywords./
for multi-occur (never tried this).?
for finding flagged entries.*
for toggling sticky agenda views.n
for all agendas andTODOs
.
The agenda view is what I use the most for reviewing all my tasks, luckily there’s a package called dashboard that also display several items from your agenda.
Configuring org-agenda-custom-commands
This is the meat of my workflow, so I should have the information I want with just pressing each keyword.
Viewing the custom agenda
today’s section
This will show on the top of my custom agenda view, showing today’s tasks.
1 2 3 4 5 6 7 8 9 10
(setq org-agenda-custom-commands `(("w" "work" ((agenda "" ((org-agenda-span 1) (org-deadline-warning-days 0) (org-agenda-block-separator nil) (org-scheduled-past-days 0) (org-agenda-day-face-function (lambda (date) 'org-agenda-date)) (org-agenda-format-date "%A %-e %B %Y") (org-agenda-overriding-header "\nToday's Agenda\n")))))))
org-agenda-span
: number of days to include in overview display, default to'week
.org-deadline-warning-days
: Number of days before expiration during which a deadline becomes active, default to14
.org-agenda-use-time-grid
: Non-nil means show a time grid in agenda schedule.org-scheduled-past-days
: Number of days to continue listing scheduled items not markedDONE
.org-agenda-format-date
: formatting for the date.This Will create a custom view
w
, with the first section marked “Today”, the\n
is for inserting new line:
Incomplete tasks section
Useful to remind me for tasks that has not yet completed.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
(setq org-agenda-custom-commands `(("w" "work" ((agenda "" ((org-agenda-span 1) (org-deadline-warning-days 0) (org-agenda-block-separator nil) (org-scheduled-past-days 0) (org-agenda-day-face-function (lambda (date) 'org-agenda-date)) (org-agenda-format-date "%A %-e %B %Y") (org-agenda-overriding-header "\nToday's Agenda\n"))) (tags-todo "*" ((org-agenda-block-separator nil) (org-agenda-skip-function '(org-agenda-skip-if-todo 'nottodo 'done)) (org-agenda-use-time-grid nil) (org-agenda-overriding-header "\nIncomplete\n")))))))
This second section is filtered by tags (though it matches everything from tags, properties, and TODO keywords). The expression
"*"
means match all keywords.The other notable filter is the
org-agenda-skip-function
, this will only show tasks that matches from the function'(org-agenda-skip-entry-if'nottodo 'done)
, which as its name suggest, skip entry ifTODO
keyword is not the type'done
(the keywords on the right side of the|
as defined here).
Next three days section
Useful to get a head start of tasks for the coming days. I used to set it for the coming week, but I’d like to stay focused.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
(setq org-agenda-custom-commands `(("w" "work" ((agenda "" ((org-agenda-span 1) (org-deadline-warning-days 0) (org-agenda-block-separator nil) (org-scheduled-past-days 0) (org-agenda-day-face-function (lambda (date) 'org-agenda-date)) (org-agenda-format-date "%A %-e %B %Y") (org-agenda-overriding-header "\nToday's Agenda\n"))) (agenda "" ((org-agenda-start-on-weekday nil) (org-agenda-start-day "+1d") (org-agenda-span 3) (org-deadline-warning-days 0) (org-agenda-block-separator nil) (org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done)) (org-agenda-overriding-header "\nNext three days\n"))) (tags-todo "*" ((org-agenda-block-separator nil) (org-agenda-skip-function '(org-agenda-skip-if-todo 'nottodo 'done)) (org-agenda-use-time-grid nil) (org-agenda-overriding-header "\nIncomplete\n")))))))
I inserted the “Next three days” section in between the “Incomplete”.
Section for upcoming deadlines
This will show all the tasks with a deadline for the next 14 days, but starting at the 4th day, since the next three days already has it section.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
(setq org-agenda-custom-commands `(("w" "work" ((agenda "" ((org-agenda-span 1) (org-deadline-warning-days 0) (org-agenda-block-separator nil) (org-scheduled-past-days 0) (org-agenda-day-face-function (lambda (date) 'org-agenda-date)) (org-agenda-format-date "%A %-e %B %Y") (org-agenda-overriding-header "\nToday's Agenda\n"))) (agenda "" ((org-agenda-start-on-weekday nil) (org-agenda-start-day "+1d") (org-agenda-span 3) (org-deadline-warning-days 0) (org-agenda-block-separator nil) (org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done)) (org-agenda-overriding-header "\nNext three days\n"))) (tags-todo "*" ((org-agenda-block-separator nil) (org-agenda-skip-function '(org-agenda-skip-if-todo 'nottodo 'done)) (org-agenda-use-time-grid nil) (org-agenda-overriding-header "\nIncomplete\n"))) (agenda "" ((org-agenda-time-grid nil) (org-agenda-start-on-weekday nil) ;; We don't want to replicate the previous section's ;; three days, so we start counting from the day after. (org-agenda-start-day "+4d") (org-agenda-span 14) (org-agenda-show-all-dates nil) (org-deadline-warning-days 0) (org-agenda-block-separator nil) (org-agenda-entry-types '(:deadline)) (org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done)) (org-agenda-overriding-header "\nUpcoming deadlines (+14d)\n")))))))
Now I have a view of my daily, weekly agenda, and list of incomplete tasks. I can easily move into each tasks with pressing
RET
(ENTER
) at each task.
Separation of work and personal tasks
I personally don’t use org-agenda for anything else beside my work stuffs. But occasionally there’s things that I put in my org files that are not work-related. For me, the easiest solution is just to use
org-tags
for all my personal tasks and useorg-agenda-tag-filter
in my agenda.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
(setq org-agenda-custom-commands `(("w" "work" ((agenda "" ((org-agenda-span 1) (org-deadline-warning-days 0) (org-agenda-block-separator nil) (org-scheduled-past-days 0) (org-agenda-day-face-function (lambda (date) 'org-agenda-date)) (org-agenda-format-date "%A %-e %B %Y") (org-agenda-overriding-header "\nToday's Agenda\n"))) (agenda "" ((org-agenda-start-on-weekday nil) (org-agenda-start-day "+1d") (org-agenda-span 3) (org-deadline-warning-days 0) (org-agenda-block-separator nil) (org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done)) (org-agenda-overriding-header "\nNext three days\n"))) (tags-todo "*" ((org-agenda-block-separator nil) (org-agenda-skip-function '(org-agenda-skip-if-todo 'nottodo 'done)) (org-agenda-use-time-grid nil) (org-agenda-overriding-header "\nIncomplete\n"))) (agenda "" ((org-agenda-time-grid nil) (org-agenda-start-on-weekday nil) ;; We don't want to replicate the previous section's ;; three days, so we start counting from the day after. (org-agenda-start-day "+4d") (org-agenda-span 14) (org-agenda-show-all-dates nil) (org-deadline-warning-days 0) (org-agenda-block-separator nil) (org-agenda-entry-types '(:deadline)) (org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done)) (org-agenda-overriding-header "\nUpcoming deadlines (+14d)\n")))) ((org-agenda-tag-filter-preset '("-personal" "-home"))))))
the
"-personal"
and"-home"
means to filter out every headlines with the tagpersonal
, andhome
, if you have many of them, just create another agenda view with that filter in reverse, using+personal
or+home
Stuck Projects
In
org-mode
term, a stuck project is a project (identified as a header) that has no defined next action, so it never shows up in the TODO list. The default value is:1 2 3 4
(setq org-stuck-projects '("+LEVEL=2/-DONE" ("TODO" "NEXT" "NEXTACTION") nil ""))
It is a list with four items:
- a tag/todo/property matching a project.
- a list of todo keywords identifying non-stuck projects.
- a list of tags identifying non-stuck projects.
- a regular expression matching non stuck projects.
The default means that a project is a level 2 headlines with the tag
PROJECT
but not if it has a todo keywordMAYBE
andDONE
, and will not be considered a stuck project if it has a todo keywordTODO
,NEXT
, orNEXTACTION
, the third and fourth item isnil
so it has no tag filter and no regular expression matcher for non-stuck projects.So I simply just use the tag
project
for tasks that I considered as a project. Using theorg-todo-keywords
that I already setup earlier, myorg-stuck-projects
is:1 2 3
(setq org-stuck-projects '("+{project*}-killed-Archives/-DONE-KILL-DELEGATED" ("TODO" "NEXT" "IDEA" "PROG") nil ""))
Then you can use org agenda to list all the stuck project with the key
#
, or with the commandM-x org-agenda #
.
Refiling and archiving
Eventually, the org-files
used in my workflow will grow larger. So I will also need to move the previous tasks, refiling them into separate categories or even separate file. And also archiving them so they won’t clutter my agenda views, and also keep my org-agenda
faster without having to check all those completed tasks.
Archiving
The main goal is to keep my main inbox file (the first entry of tasks) empty as soon as possible. This is where org-archive comes handy. The flow that I have in mind is to create a monthly file, perhaps in a headline consisting of YYYY/MM
structure. The refiled entries are still monitored by org-agenda. I’d like to have some kind of agenda view for these files for reviewing purpose, perhaps maybe exporting them to different formats.
|
|
This will set the archive location to a file named archives.org
inside my org-directory
, and within a first level headline named “Archived Tasks”
Refiling
Still with the goal of having an unclutter inbox file, I’m using org-refile
feature to move tasks from my inbox into another file, mainly for tasks that need (or waiting for) several steps to complete. Mostly though, I use org-refile
in order to categorize my tasks, for examples I prefer to put tasks that are related to projects (in term of my work project), into a file named projects.org
inside my org-directory
, and routine tasks into routines.org
, and my personal stuffs in personal.org
|
|
org-refile-use-outline-path
- this is set to
'file
to provide the file name as the refile target. Necessary since I’m using multiple files. org-outline-path-complete-in-steps
- set to
nil
so the completions won’t be set per step (filename -> headlines). Just to speed up the process. :maxlevel
- limits the level of headlines considered to be a target. A max level of 1 means only the top-level headlines. This also means that all the targets above can be set into one file (e.g.
refile.org
), and create a top-level headlines as the categories.
We’ll also need to add a hook to make sure that the target buffer is saved after the refiling process.
|
|
Things of interest
- Exporting org-agenda to thunderdbird
- I use thunderbird, and also have setup my thunderbird calendar to sync my Outlook calendars using davmail.
Using org-capture
Of course all of the above would be useless if I have to manually create a task. At least I would like to have an org-capture template to make this easier.
|
|
Capturing with templates
Let say there are some entries that usually have a similar format, we can provide a template for those entries. Name this request.template
and put it inside the org-directory
.
|
|
This will create a template for a 2nd level heading, with org properties and a logbook drawer. But we also need some inputs:
%^{User}
- prompt for User.
%^{Category|Meeting|Purchage|Repair|Assistance}
- Prompt for input with predefined values.
%a
- Annotation, normally the link created with
org-store-link
. %U
- inactive timestamp for state tracking, only needed for the first time, will be updated automatically every time there’s a state change.
list started with [ ]
means that it’s a checkbox list, we can change the state to [x]
using C-c C-c
.
|
|
Things of interest
- Using context-aware capture-templates
- the link is not just about
org-capture
.
Synchronization, Capture Methods and everything else
I mainly use syncthing for synchronizing my org-directory
across my devices. It has support for android, on which I use orgzly mostly for viewing the org files. Once you’ve set the repository inside orgzly to point to org-directory
(which already synced by syncthing), you’re ready to go. Also don’t forget to match the todo keywords with the one you’ve set in Emacs. The downside is you cannot attach to the org-file while in orgzly.
And, depending on your android version, syncthing cannot sync properly on some filesystems. So it’s better to store your sync directory on the device internal storage than the external one. With that being said, I am still exploring other possibilities:
- google’s keep
- I never got the comfort of typing or navigating with my finger on a touchscreen. And to me, Android is such a mess by trying to pick comfort over functionality. Google Keep is the one app that (was) very simple and the only one app that I still consider a Google App. I can sync a note between my phone and my pc, I can also attach media to it (try taking photos of 41 printers of the same model, and guess each location, etc). But here comes the new UI updates…
- Firefox
- There used to be an editor war, now it just plain war. Now I just use Firefox just because I choose to use Firefox.
org-protocol
allows me to capture a link in Firefox intoorg-mode
just by using a bookmark.This allows me to easily insert links into my
org-capture
.
org-mode extensions
Although all the configuration listed above is enough for my task management workflow, there are many packages for Emacs (builtin or external) to enhance your org-mode experience. Here are some of them:
Evil-mode
I made a separate post for this package. If you’re coming from Vim, this is mandatory. If you’re not, try the default Emacs keybindings first, if your pinky fingers are not long enough, try this package.
|
|
org-fancy-priorities
|
|
org-modern
This package implements a modern style for your Org buffers using font locking and text properties. The package styles headlines, keywords, tables and source blocks. The styling is configurable, you can enable, disable or modify the style of each syntax element individually via the org-modern customization group.
|
|
builtin packages
saveplace
|
|
When you visit a file, point goes to the last place where it was when you previously visited the save file.
savehist
Save the minibuffer history
|
|
various files
configuration
|
|
find-file-visit-truename
- if the visited file is a symlink, it will find the truename of the file instead.
version-control
- make numeric backup versions unconditionally.
backup-by-copying
- always use copying to create backup files.
delete-old-versions
- delete excess backup versions silently
By using another instance of Emacs, but with a specific command arguments:
1
emacs --init-directory=/dev/null
This will ensure Emacs is started with no user configuration. ↩︎