No Frills Daily Project Management

2024-01-07

In this post I document a setup to manage projects with org-mode and org-ql.

Context

At work, we share an etherpad document as a support for two main ceremonies:

  • Daily standup meeting where each members provides an update on their work.
  • Semi-monthly review meeting where we summarize our work for the broader organization.

Without an organizational system, we can simply recall what happened and fill out the document right before the meeting starts. It is more efficient to implement a system to keep track of tasks as they come up, so that you don’t have to rely solely on your memory.

Introducing org-mode

org-mode is arguably the most advanced system for taking notes and organizing things. It is a free software that comes with Emacs.

In the next section I focus on the todo feature, but note that org-mode comes with many additional features such as:

  • Calendar, agenda and clocking.
  • Structural editor with markup language.
  • Literate source code editor with evaluation similar to Jupiter notebooks.

Capturing tasks

Use the org-capture command to enter a task. This can happen in one of the following situations:

  • To record something that needs to be done, e.g. a planned task like “implement a feature”.
  • To record something that has been completed, e.g. an unplanned task like “fix the logserver”.

To tell org-capture where to write down a task, create the following template at ~/org/projects.org:

* Inbox

* Monocle changemetrics.io
:PROPERTIES:
:CATEGORY: Monocle
:END:

+ Opendev
:PROPERTIES:
:CATEGORY: Opendev
:END:

This document contains three headings showing how properties can be attached to create categories. Here is how that looks like in nano-emacs:

nano-org-init

Then in ~/.emacs.el write the following configuration:

;; Configure where tasks are written
(setq org-capture-templates
      '(
        ("t" "todo" entry (file+headline "~/org/projects.org" "Inbox")
         "* TODO %?\n/Entered on/ %U\n")
        ))

;; Define a new helper function
(defun tc/org-capture-todo ()
  "Directly capture a todo."
  (interactive)
  (org-capture nil "t"))

;; Press F5 to capture a task (same key as quicksave in KSP)
(define-key global-map (kbd "<f5>") 'tc/org-capture-todo)

Now pressing F5 create the following window:

nano-capture

After filling a description of the task, you have three options:

  • C-c C-c org-capture-finalize: add the task to the inbox.
  • C-c C-w org-capture-refile: refile the task to a project.
  • C-c C-k org-capture-kill: abort the capture process and close the window.

Then your projects.org documents is updated with:

nano-org-inbox

Managing tasks

Use M-x org-refile to move a task, and press tab to get a list of destination:

nano-org-refile

For example, pressing M tab enter moves the task to the monocle project.

To change the status of tasks use M-x org-todo, this will cycle between NA, TODO and DONE. Note that this can be used to turn any heading into a task too.

In ~/.emacs.el add the following setting to attach a CLOSED property when a task is done.

;; Keep track of when the task was completed
(setq org-log-done 'time)

Running M-x org-todo on the example task results in:

nano-org-done

Listing tasks

To list tasks, configure where to look for tasks:

;; Tell org-agenda where are the org files
(setq org-agenda-files '("~/org"))

Then running M-x org-todo-list display the global list of tasks:

nano-org-list

Click on a task to jump to its location in the projects.org file. You can also manage the task directly from the list, e.g. using org-todo to change its status.

You can also run M-x org-agenda-filter to narrow down the listing by category.

Creating report with org-ql

org-ql lets you search the tasks to produce custom report.

Install the library by adding the following to your ~/.emacs.el:

;; Install org-ql through melpa
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)
(package-install 'org-ql)

While you can use org-ql interactively, for example by running M-x org-ql-search, it’s also possible to fully customize the output using Emacs native configuration language.

For example, a daily standup report needs to look like this:

YYYY-MM-DD

$USER:
* entry

Here is how to render your tasks for this particular format:

;; string manipulation library from https://github.com/magnars/s.el
(require 's)
(require 'org-ql)

;; The inverse of s-lines
(defun s-unlines (xs) (s-join "\n" xs))

(defun tc/daily-format-item (item)
  "Format 'org-ql-select' output. ITEM is a prop list."
  (let* ((properties (cadr item))
         (title (plist-get properties :raw-value))
         (category (org-entry-get (plist-get properties :org-marker) "CATEGORY")))
    (format "* %s - %s" (s-pad-left 13 " " category) title)))

(defun tc/daily-format (items)
  "Format all ITEMS."
  (let* ((today (format-time-string "%Y-%m-%d"))
         (header (list today "" user-login-name))
         (body (mapcar 'tc/daily-format-item items)))
    (s-unlines (append header body))))

(defun tc/mk-daily-report ()
  "Produce a report for team daily."
  (interactive)
  ;; todo: adjust the from timestamp to a single day for tue-wed-thu-fri
  (let* ((entries (org-ql-select "~/org/projects.org"
                    '(and (done) (ts :from -3 :to today))
                    :action 'element-with-markers))
         (report (tc/daily-format entries))
         (*buffer* (get-buffer-create "*tc/daily*")))
    (with-current-buffer *buffer*
      (erase-buffer)
      (insert report))
    (switch-to-buffer-other-window *buffer*)))

(define-key global-map (kbd "<f6>") 'tc/mk-daily-report)

Then running M-x tc/mk-daily-report creates a new window with the following content, ready to be shared with the team:

nano-org-report

Conclusion

This post demonstrated a minimal usage of org-mode to perform project management. To learn more about org-mode, I recommend the following guide by Nicolas P. Rougier: Get Things Done with Emacs.

To learn more about emacs in general, I recommend starting with nano-emacs to run the help-with-tutorial.

Links to this page
#emacs #blog