My simple org mode system
Organize your life
Org mode has so many useful features, in this year of Emacs I integrated the following in my life:
- Literate emacs configuration (you can see the HTMl export of mine here )
- Literate programming (explained in this previous blog post)
- Publish a static blog (explained in this previous blog post)
- Knowledge library
- Task management
In this post I will focus on the GTD (Getting Things Done) org facilities and how I interface with them.
The first org mode abstraction is an headline with a TODO status.
The first natural step is then to create an org file (e.g.
todos.org) where we can monitor our TODO headings.
When we complete one, we set it to DONE and archive it with
* TODO finish to write slides * DONE add docs
This all sounds great, except..
- I don't know what tasks are important
- I forget to check the file for days, also forgetting tasks
- I am not good at capturing my tasks in this file during my day.
Solving any of these 3 problems is useless, we need to solve all three of them.
Problem 1. is solved by scheduling a task.
You commit to do a task on a certain day (e.g. today, or tomorrow. Why wait?) and you execute
org-schedule on that heading.
* TODO finish to write slides SCHEDULED: <2021-03-02 Tue> * DONE add docs
This leads to the next big org abstraction, the agenda!
When you call
org-agenda-list you will see all the scheduled TODOs for the week (including the task you just scheduled for today).
This is now your agenda, it would be great to follow it and to complete the tasks that you have just marked as important!
Let's tackle problem 2. by introducing habits!! Let's say we want to check our
todos.org every 3 days?
Then we can mark it as an habit:
* TODO finish to write slides SCHEDULED: <2021-01-24 Tue> * DONE add docs * TODO Check todos.org (start with #inbox) SCHEDULED: <2021-01-24 Sun .+2d/4d> :PROPERTIES: :STYLE: habit :LAST_REPEAT: [2021-01-22 Fri 18:08] :END: - State "DONE" from "TODO" [2021-01-22 Fri 18:08] - State "DONE" from "TODO" [2021-01-18 Mon 20:53] - State "DONE" from "TODO" [2021-01-17 Sun 21:40]
Now it will be scheduled in the agenda once every 3 days.. Now, if we only weren't so bad at checking our agendas…
Show agenda in emacs-dashboard
In the previous section we introduced the fundamental blocks of org GTD system: scheduled tasks, habits and the agenda.
I use the
dashboard package so that my first buffer is a "dashboard" which provides
a quick access to weekly agenda and my next tasks.
Here is my configuration for the package (you can read the up-to-date configuration here):
(use-package dashboard :demand :init (setq initial-buffer-choice (lambda () (get-buffer "*dashboard*"))) (setq dashboard-center-content t) (setq dashboard-projects-backend 'projectile) (setq dashboard-set-heading-icons t) (setq dashboard-set-file-icons t) (setq dashboard-banner-logo-title nil) (setq dashboard-set-footer nil) (setq dashboard-set-navigator t) (defun lc/is-after-17-or-weekends? () (or (-> (nth 3 (split-string (current-time-string) " ")) ; time of the day e.g. 18 (substring 0 2) (string-to-number) (> 16)) (-> (substring (current-time-string) 0 3) ; day of the week e.g. Fri (member '("Sat" "Sun"))))) ;; exclude work items after 17 and on weekends (run-at-time "00:00" (* 60 60 24) (lambda () (if (lc/is-after-17-or-weekends?) (setq dashboard-match-agenda-entry "life|habits" dashboard-match-next-entry "TODO=\"NEXT\"-work") (setq dashboard-match-agenda-entry "work|life|habits" dashboard-match-next-entry "TODO=\"NEXT\"")))) ;; buttons above agenda (setq dashboard-navigator-buttons `((;; Github (,(all-the-icons-octicon "mark-github" :height 1.1 :v-adjust 0.0) "Github" "Go to wondercast" (lambda (&rest _) (browse-url "https://github.com/Maersk-Global/wondercast"))) ;; Codebase (,(all-the-icons-faicon "briefcase" :height 1.1 :v-adjust -0.1) "JIRA" "Go to Kanban" (lambda (&rest _) (browse-url "https://jira.maerskdev.net/secure/RapidBoard.jspa?rapidView=6378&projectKey=AVOC&quickFilter=15697"))) ;; Perspectives (,(all-the-icons-octicon "history" :height 1.1 :v-adjust 0.0) "Restore" "Restore" (lambda (&rest _) (persp-state-load persp-state-default-file))) ))) ;; show next tasks in dashboard (defun lc/dashboard-get-next () "Get agenda items for today or for a week from now." (org-compile-prefix-format 'agenda) (org-map-entries 'dashboard-agenda-entry-format dashboard-match-next-entry 'agenda)) (defun lc/dashboard-insert-next (list-size) "Add the list of LIST-SIZE items of next tasks" (require 'org-agenda) (let ((next (lc/dashboard-get-next))) (dashboard-insert-section "Next tasks" next list-size "n" `(lambda (&rest ignore) (let ((buffer (find-file-other-window (nth 2 ',el)))) (with-current-buffer buffer (goto-char (nth 1 ',el)) (switch-to-buffer buffer)))) (format "%s" (nth 0 el))))) :config (dashboard-setup-startup-hook) (set-face-attribute 'dashboard-items-face nil :height (lc/get-font-size)) ;; show next tasks in dashboard (add-to-list 'dashboard-item-generators '(next . lc/dashboard-insert-next)) (setq dashboard-items '((agenda . 5) (next . 5) (projects . 5))))
There are a few useful features here:
- Show weekly agenda, i.e. tasks that I have scheduled for the coming week.
- Filter agenda items according to time of day and day of week. Today is Sunday so in the screenshot you don't see my work tasks.
- Show "NEXT" unscheduled tasks. Think of these tasks as your backlog, the next tasks you should schedule.
- BONUS: nice buttons that brings you to a website or restore the latest session (if you want to know more about this one, read here).
The dashboard is the reminder to myself about my tasks.
When I start up Emacs, I will find my tasks staring right at me.
If I am in a good mood, I will review my
todo.org file, schedule some more, put some to "DONE".
As mentioned, I keep all my tasks in one file called
todo.org, which is included in my
I categorize my tasks in "projects". Two example projects are "Life" and "Work".
Each project is then categorized in subprojects. An example subproject for "Work" could be a user story I am working on. For a subproject I would have individual headings corresponding to tasks.
Here a practical example:
* Work [0/2] :PROPERTIES: :COOKIE_DATA: todo recursive :CATEGORY: work :END: ** Recursive least squares model [0/2] *** TODO Implement RLS model *** TODO Validate results
So we model user stories as subheadings and we categorize them within "projects".
- The header properties set the category to work. The
recursivepart make it so that subheadings/subprojects can inherit it.
- If you put
[/]in your header title, you will get for free a count of how many you have completed and the total.
work category can then be used to filter agenda views like described in the previous section.
Agenda and notifications on your iPhone
Ok, the system we configured on Emacs seems pretty solid. What about when we are away from the laptop?
Wouldn't it be great to be able to view your agenda on the go, get push notifications? The BeOrg app for iOS goes pretty close to what I need from it.
I keep my
org folder on Dropbox and version control.
BeOrg can sync from Dropbox without hassle.
I hardly ever edit files on the go, I neved had a Dropbox conflict.
I can see my agenda (same that I see in the dashboard) and I get notifications for scheduled tasks. I can read org files on the go, nice to quickly check up on some notes, recipes or guitar chords. Highly recommended.
Capture new ideas from your iPhone
In the first section we have described 3 problems but we still haven't solved the third:
- I am not good at capturing my tasks in this file during my day.
I found a nice way to capture ideas from my iPhone. That is achieved through the Drafts app for iOS.
You can get an "action" for free called Org-mode capture. Once you set it up on your iPhone, you can write quick notes and send them to a file in Dropbox.
Unfortunately you can't edit the action template unless you pay for the premium tier of Drafts.
I am personally fine with leaving the default, which will write to
I can just create symlink from
Notes to my
org folder in Dropbox.
I usually send a bunch of ideas during my day to my "mobile inbox" and then refile (
org-refile) them to appropriate headers.
This was the last trick, I hope you found the article useful! If something was not clear, please leave a comment below.