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

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

1
2
3
4
(global-set-key (kbd "C-c l") #'org-store-link)
(global-set-key (kbd "C-c a") #'org-agenda)
(global-set-key (kbd "C-c c") #'org-capture)
(global-set-key (kbd "C-c C") #'org-capture-goto-last-stored)
Code Snippet 1: suggested 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:

1
(setq org-directory (expand-file-name "org" user-emacs-directory))
Code Snippet 2: set the location of org-directory inside user-emacs-directory

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

1
(setq org-directory (expand-file-name "org" (getenv "HOME"))) ;; ~/org/
Code Snippet 3: set the location of org-directory on the root of your home directory

Assuming your user-emacs-directory is in ~/.emacs.d~, then your org-directory is ~/.emacs.d/org

1
(setq org-agenda-files (list org-directory))
Code Snippet 4: set the location of org-agenda-files

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?

1
(setq org-archive-location (concat (expand-file-name "archives.org" org-directory) "::datetree/* Archived Tasks"))
Code Snippet 5: An example of setting the org-archive-location to a file archives.org inside the org-directory

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:

Table 1: my todo keywords
TODO KeywordWhat it is
TODOTasks that are not started, also not planned. There can be many of them.
NEXTTasks that are planned to do immediately.
WAITTasks that needs other form of interaction in order for it to be set as PROG or DONE or KILL.
PROGTasks 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.
HOLDThe 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:

Table 2: keywords with no further actions
TODO keywordWhat it is
DONEGG, well played!
DELEGATEDI got someone else doing my job, GG, well played!
KILLCancelled, or my boss gave me a task beyond my paygrade

Translate these into Emacs Lisp:

1
2
(setq org-todo-keywords
      '((sequence "TODO(t!)" "NEXT(n!)" "PROG(p!)" "WAIT(w!)" "HOLD(h!)" "|" "DONE(d!)" "DELEGATED(l!)" "KILL(k!)")))
Code Snippet 6: defining my own org-todo-keywords
  • 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]
    
    Code Snippet 7: example of state changes log

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.

1
2
3
4
5
6
7
8
9
(setq org-priority-highest ?A
      org-priority-lowest ?D
      org-priority-default ?B)

(setq org-priority-faces
      '((?A . (:foreground "#bf616a" :weight bold :underline t))
        (?B . (:foreground "#d08770" :weight bold :underline t))
        (?C . (:foreground "#4c566a" :weight bold :underline t))
        (?D . (:foreground "#3b4252" :weight bold :underline t))))
Code Snippet 8: org-priority setup

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:

1
2
(setq org-use-tag-inheritance t
      org-tags-exclude-from-inheritance '("crypt"))

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.

1
2
3
* TODO test
DEADLINE: <2024-03-14 Thu>
- State "TODO"       from              [2024-03-14 Thu 22:10]
Code Snippet 9: TODO task with a deadline

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.

1
2
3
* TODO test
SCHEDULED: <2024-03-16 Sat 09:00>
- State "TODO"       from              [2024-03-14 Thu 22:10]
Code Snippet 10: TODO task with a schedule

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, key t.
  • Matching queries of tags, properties, or TODO keywords. With the key m.
  • s, search for keywords.
  • / for multi-occur (never tried this).
  • ? for finding flagged entries.
  • * for toggling sticky agenda views.
  • n for all agendas and TODOs.

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.

Figure 1: my dashboard

Figure 1: my dashboard

Figure 2: Vanilla Emacs org-agenda

Figure 2: Vanilla Emacs org-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 to 14.

      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 marked DONE.

      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:

      Figure 3: today&rsquo;s view

      Figure 3: today’s view

    • 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")))))))
      
      Code Snippet 11: Incomplete tasks section addition

      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 if TODO keyword is not the type 'done (the keywords on the right side of the | as defined here).

      Figure 4: incomplete section

      Figure 4: incomplete section

    • 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”.

      Figure 5: next 3 days

      Figure 5: next 3 days

    • 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")))))))
      
      Code Snippet 12: upcoming deadlines
      Figure 6: the modified org-agenda-custom-commands

      Figure 6: the modified org-agenda-custom-commands

      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 use org-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"))))))
      
      Code Snippet 13: filter by tag

      the "-personal" and "-home" means to filter out every headlines with the tag personal, and home, if you have many of them, just create another agenda view with that filter in reverse, using +personal or +home

      Figure 7: upcoming deadlines

      Figure 7: upcoming deadlines

    • 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 ""))
      
      Code Snippet 14: default org-stuck-projects

      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 keyword MAYBE and DONE, and will not be considered a stuck project if it has a todo keyword TODO, NEXT, or NEXTACTION, the third and fourth item is nil 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 the org-todo-keywords that I already setup earlier, my org-stuck-projects is:

      1
      2
      3
      
      (setq org-stuck-projects '("+{project*}-killed-Archives/-DONE-KILL-DELEGATED"
                            ("TODO" "NEXT" "IDEA" "PROG")
                            nil ""))
      
      Code Snippet 15: my org-stuck-projects

      Then you can use org agenda to list all the stuck project with the key #, or with the command M-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.

1
(setq org-archive-location  (concat org-directory  "/archive.org::datetree/* Archived Tasks"))
Code Snippet 16: my org-archive setup

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

1
2
3
4
5
6
(setq org-refile-targets
      `((,(expand-file-name "projects.org" org-directory) :maxlevel . 1)
        (,(expand-file-name "routines.org" org-directory) :maxlevel . 1)
        (,(expand-file-name "personal.org" org-directory) :maxlevel . 1))
      org-refile-use-outline-path 'file
      org-outline-path-complete-in-steps nil)
Code Snippet 17: my org-refile setup
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.

1
(add-hook 'org-after-refile-insert-hook #'save-buffer)
Code Snippet 18: refile hook

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.

1
2
3
4
5
(require 'org-capture)
(setq org-capture-templates
      `(("i" "Inbox" entry
         (file+headline ,(expand-file-name "inbox.org" org-directory) "Inbox")
         "** %?\n%i\n%a" :prepend t :jump-to-captured t)))
Code Snippet 19: org-capture-templates

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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
** TODO %?
:PROPERTIES:
:USER: %^{User}
:UNIT: %^{Unit|MKN|GMN|STN}
:DATE: %T
:LOCATION:
:CATEGORY: %^{Category|Meeting|Purchase|Repair|Assistance|Tech Issue|Complaints|Account Management}
:REQUEST_VIA: %^{Request via|In Person|Phone/Messaging|Mail}
:ITEM: %^{Item}
:QTY: %^{Quantity|1}
:LINK: %a
:END:
:LOGBOOK:
- State "TODO"		from		%U
:END:

*** Requirements
- [ ] Escalation
- [ ] Approval
- [ ] Vendor

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.

1
2
3
(add-to-list 'org-capture-templates
             `("r" "Request" entry (file+headline ,(expand-file-name "inbox.org" org-directory) "Request")
               (file ,(expand-file-name "request.template" org-directory))))
Code Snippet 20: the org-capture-templates
Figure 9: org-capture with a predefined template

Figure 9: org-capture with a predefined template

Figure 10: the content of the template

Figure 10: the content of the template

Figure 11: Prompt with completion

Figure 11: Prompt with completion

Figure 12: content of the capture target

Figure 12: content of the capture target

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 into org-mode just by using a bookmark.

Figure 14: org-protocol capture

Figure 14: org-protocol capture

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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
(use-package evil
  :ensure t
  :init
  (setq evil-want-integration t) ;; This is optional since it's already set to t by default.
  (setq evil-want-keybinding nil)
  :config
  (evil-mode 1))

(use-package evil-collection
  :after evil
  :ensure t
  :config
  (evil-collection-init)
  (with-eval-after-load 'org-agenda
    (evil-set-initial-state #'org-agenda-mode 'normal)
    (evil-define-key '(normal visual) org-agenda-mode-map
      "q" 'org-agenda-quit
      "Q" 'org-agenda-quit
      (kbd "<return>") 'org-agenda-switch-to
      "t" 'org-agenda-todo
      "gr" 'org-agenda-redo-all)))
Code Snippet 21: recommended evil configuration

org-fancy-priorities

1
2
3
4
5
6
(use-package org-fancy-priorities
  :ensure t
  :hook
  (org-mode . org-fancy-priorities-mode)
  :config
  (setq org-fancy-priorities-list '("⚡" "⬆" "⬇" "☕")))
Figure 15: image from their readme page

Figure 15: image from their readme page

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.

 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
37
38
39
40
41
42
43
(use-package org-modern
  :ensure t
  :init
  (menu-bar-mode -1)
  (tool-bar-mode -1)
  (scroll-bar-mode -1)
  (load-theme 'modus-vivendi t)
  :config
  (set-face-attribute 'org-modern-symbol nil :family "Iosevka Nerd Font")
  (set-face-attribute 'default nil :family "Iosevka Nerd Font Mono")
  (set-face-attribute 'variable-pitch nil :family "Iosevka Nerd Font Mono")
  (modify-all-frames-parameters
   '((right-divider-width . 40)
     (internal-border-width . 40)))
  (dolist (face '(window-divider
                  window-divider-first-pixel
                  window-divider-last-pixel))
    (face-spec-reset-face face)
    (set-face-foreground face (face-attribute 'default :background)))
  (set-face-background 'fringe (face-attribute 'default :background))
  (setq
   ;; Edit settings
   org-auto-align-tags nil
   org-tags-column 0
   org-catch-invisible-edits 'show-and-error
   org-special-ctrl-a/e t
   org-insert-heading-respect-content t

   ;; Org styling, hide markup etc.
   org-hide-emphasis-markers t
   org-pretty-entities t
   org-ellipsis "…"

   ;; Agenda styling
   org-agenda-tags-column 0
   org-agenda-block-separator ?─
   org-agenda-time-grid
   '((daily today require-timed)
     (800 1000 1200 1400 1600 1800 2000)
     " ┄┄┄┄┄ " "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄")
   org-agenda-current-time-string
   "◀── now ─────────────────────────────────────────────────")
  (global-org-modern-mode))
Code Snippet 22: org-modern configuration (mainly from their github page)
Figure 17: org-modern agenda

Figure 17: org-modern agenda

builtin packages

saveplace

1
2
3
4
5
(use-package saveplace
  :init
  (save-place-mode 1)
  :custom
  (save-place-file (expand-file-name "places" user-emacs-directory)))

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
(use-package savehist
  :init
  (savehist-mode 1)
  :custom
  (savehist-file (expand-file-name "history" user-emacs-directory))
  (savehist-coding-system 'utf-8)
  (savehist-additional-variables
   '(evil-jumps-history
     kill-ring
     register-alist
     mark-ring
     global-mark-ring
     search-ring
     regexp-search-ring)))

various files configuration

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
(use-package files
  :custom
  (find-file-visit-truename t)
  (version-control t)
  (backup-by-copying t)
  (delete-old-versions t)
  (kept-new-versions 6)
  (kept-old-versions 2)
  (auto-save-include-big-deletions t)
  (auto-save-list-file-prefix (expand-file-name ".autosave/" user-emacs-directory))
  (backup-directory-alist `(("." . ,(expand-file-name ".backup" user-emacs-directory)))))
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

  1. 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. ↩︎