• Stars
    star
    441
  • Rank 98,861 (Top 2 %)
  • Language
    CSS
  • Created about 4 years ago
  • Updated 10 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Get Things Done with Emacs

Get Things Done with Emacs

Introduction

Before I start describing how I organize my professional life using Emacs and org-mode, let me introduce myself. Iā€™m a researcher in computational neuroscience working at the Institute of Neurodegenerative Diseases in Bordeaux (France). As such, my main tasks during a typical day are meetings with my PhD students (physical or online), team and grant meetings (physical or online), development (GitHub), reading (online), reviewing (online) and writing (books, papers, grants, notes, etc). Iā€™m also co-founder and editor in chief for ReScience C and ReScience X and Iā€™m involved in several academic and open source projects. I receive approximately 100 mails and 10 GitHub notifications a day.

As of September 2020, Iā€™m supervising five PhD students (two first year, one second year, one third year and one finishing). Iā€™m currently writing a book (Scientific Visualization ā€” Python & Matplotlib), handling the simulatenous writing of 6 academic papers (at various stages), while preparing a SciFi festival (Hypermondes), a hackaton (ReproHack @ Bordeaux), a workshop (Ten Years Reproducibility Challenge) and a summer school (ASPP 2021) to be held in Bordeaux in 2021.

All these activities requires some organisation.

Get Things Done

Iā€™ve decided some weeks ago to (try to) adopt the method of David Allen named ā€œGet Things Doneā€ (GTD). A lot of people were giving very positive feedback about this method and there are a lot of related resources online, including several Emacs/org-mode setup. This helped me a lot to design my own setup since I did not read the book, but I found a nice summary:

  1. Capture anything that crosses your mind, nothing is too big or small.
  2. Clarify what youā€™ve captured into clear and concrete action steps.
  3. Organize and put everything into the right place.
  4. Review, update, and revise your lists.
  5. Engage Get to work on the important stuff.

Then I read a lot of other Emacs specific resources that were incredibly useful but also a bit complex because people introduced their full setup making it difficult to understand it sometime. Since Iā€™m still in the setup phase, Iā€™ve decided to document the process while designing it, hoping it will be helpful for others.

If you want to read my current full setup, just go the end of this document. Else, you can read each section and discover the process step by step. Note that this means weā€™ll write some parts only to be rewritten later with some improvements, just for the sake of clarity.

About this document

In all the following section, Iā€™ll suppose youā€™re familiar with emacs (of course) and knows bit of org-mode. If this is not the case, you can follow the different links Iā€™ve inserted. They point to the relevant section in the org-mode manual. Weā€™ll start with a Vanilla emacs without any initial configuration (ā€œ/emacs -q ā€“ GTD.elā€/) such that you should obtain the same result as me. GTD.el will be given in each section.

The address of this document is: https://www.labri.fr/perso/nrougier/GTD/index.html
The sources of this document is: https://github.com/rougier/emacs-GTD

License

This document has been written in org mode (=GTD.org=) using a customized CSS stylesheet (=GTD.css=) released (both) under a CC-BY 4.0 international license. Feel free to re-use it if you like it.

Resources

Here are various resources that helped me to design my workflow:

  • Org-mode Workflow: A Preview by Jethro Kuan (2020)

    This is going to be a multi-part series on Emacs and org-mode. This is also going to be a really long series, so before we begin I want to give you an idea of what to expect. What Iā€™m about to present is a workflow Iā€™ve tweaked over several years. It is a workflow that has constantly evolved to adapt to my varying needs. At the time of writing, I have completed 3478 todo items, and written over 29000 lines in my personal knowledge base.

  • Orgmode for GTD by Nicolas Petton (2017)

    Iā€™ve been using Orgmode to implement the GTD methodology for the last 4 years. Rather than explaining the GTD methodology itself or how Orgmode works, in this post Iā€™ll detail how I use Orgmode to implement GTD. If you donā€™t know Orgmode and are curious about it, you should head to its website first.

  • Org Mode - Organize Your Life In Plain Text! by Bernt Hansen (2015)

    I have been using org-mode as my personal information manager for years now. I started small with just the default TODO and DONE keywords. I added small changes to my workflow and over time it evolved into what is described by this document. I still change my workflow and try new things regularly. This document describes mature workflows in my current org-mode setup. I tend to document changes to my workflow 30 days after implementing them (assuming they are still around at that point) so that the new workflow has a chance to mature.

  • How I use Emacs and Org-mode to implement GTD by Charles Cave (2009)

    ā€œGetting Things Doneā€ is a book by David Allen in which he describes a work-life management system developed after twenty years of consulting work. The promise of GTD is ā€œStress-free productivityā€ and developing a calm state of mind in a state of readiness. Allenā€™s second book, ā€œReady for Anythingā€ elaborates on these principles in a series of essays. The effectiveness of GTD lies in taking a complete and current inventory of all your commitments, then organizing and reviewing this information regularly in a systematic way. Your work and life can then be viewed from different levels of detail allowing you to make choices about what to do (and not do) at any moment.

And of course, the org-mode documentation helped me alot.

Org is a mode for keeping notes, maintaining TODO lists, and doing project planning with a fast and effective plain-text system. It is also an authoring and publishing system, and it supports working with source code for literal programming and reproducible research.

Inbox

Basic setup

The first step I was interested in was a way to quickly capture any idea that I may have during the day. My goal was to have a non-disruptive process, that is, type a key sequence to enter capture mode, type some text and then just forget about it. More specifically, I did not want to have to think where I would store this text nor thinking about any related information such as tags or date. I chose to store theses ideas in a ~/Documents/org/inbox.org file:

(setq org-directory "~/Documents/org")
(setq org-agenda-files (list "inbox.org"))

My initial inbox.org reads (weā€™ll modify it later):

#+STARTUP: content showstars indent
#+FILETAGS: inbox

The STARTUP line defines some buffer settings (initial visibility, indent mode and star visibility) while the FILETAGS line defines a common tag that will be inherited by all entries (inbox in this case).

then we can setup a specific capture template for inbox:

(setq org-capture-templates
       `(("i" "Inbox" entry  (file "inbox.org")
        ,(concat "* TODO %?\n"
                 "/Entered on/ %U"))))

and setup a keyboard shortcut (C-c c):

(define-key global-map (kbd "C-c c") 'org-capture)

Note that this binding will invoke the org capture menu and to add something to the inbox, the full sequence is C-c c i. Since I intend to use it quite often, I prefer to have shorter bindings:

(defun org-capture-inbox ()
     (interactive)
     (call-interactively 'org-store-link)
     (org-capture nil "i"))

(define-key global-map (kbd "C-c i") 'org-capture-inbox)

Working with mail

For a long time, Iā€™ve been using my mail inbox as a todo box, i.e. a collection of emails that call for action. Any mail that was not archived requested an answer in the short or long term. I doubt this is the recommended way of handling the inbox (but is there any?) but since I decided to move to GTD, it was also the opportunity to handle my mail differently. A few months back, I moved away from the default system email client on my OSX machine and started to use the almighty mu4e (mu for emacs) that provides a very smooth capture integration. We can thus add a new template for quickly capturing a ā€œReply toā€ action to be filed in the inbox.

(setq org-capture-templates
      `(("i" "Inbox" entry  (file "inbox.org")
        ,(concat "* TODO %?\n"
                 "/Entered on/ %U"))
        ("@" "Inbox [mu4e]" entry (file "inbox.org")
        ,(concat "* TODO Process \"%a\" %?\n"
                 "/Entered on/ %U"))))

We can now define a binding for headers and view mode:

(define-key mu4e-headers-mode-map (kbd "C-c c") 'mu4e-org-store-and-capture)
(define-key mu4e-view-mode-map    (kbd "C-c c") 'mu4e-org-store-and-capture)

To register a reply action, the full sequence is thus C-c c @. Since Iā€™m lazy, letā€™s shorten it to C-c i:

(defun org-capture-mail ()
  (interactive)
  (call-interactively 'org-store-link)
  (org-capture nil "@"))

(define-key mu4e-headers-mode-map (kbd "C-c i") 'org-capture-mail)
(define-key mu4e-view-mode-map    (kbd "C-c i") 'org-capture-mail)

Last thing is a small hook to tell org-capture to use the full window instead of splitting the current window. This is not mandatory at all and mostly depends on your taste.

(add-hook 'org-capture-mode-hook 'delete-other-windows)

Capturing tasks

Any time you want to enter something in your inbox, be it a note or something related to a mail, just type C-c i and you should see the following capture window:

*Capture buffer. Finish 'C-c C-c', refile 'C-c C-w', abort 'C-c C-k'.*
* TODO +_+
  /Entered on [2020-09-11 Fri 07:53]/

For mail related note, you donā€™t have to do anything:

*Capture buffer. Finish 'C-c C-c', refile 'C-c C-w', abort 'C-c C-k'.*
* TODO Process "Adaptive Computation Time ā€¦" +_+
  /Entered on [2020-09-08 Tue 08:51]/

My inbox notes are generally short (verb + subject) because I use a daily review and it is generally enough information for later processing. To give you an idea, here is my current inbox (2020-09-11 Fri). Note that all the Process entries links to the relevant mail.

#+STARTUP: content showstars indent
#+FILETAGS: inbox
* TODO Organize bibliography ā€¦
* TODO Process "Adaptive Computation Time ā€¦" ā€¦
* TODO Process "Relevant paper" ā€¦
* TODO Mail F.Wagner about team talk ā€¦
* TODO Buy "Canon printer" ā€¦
* TODO Process "ICDL oral presentation" ā€¦
* TODO Write discussion (plasticity paper) ā€¦
* TODO Compute VSOM Ī“xĪ“y representation ā€¦

During the review, some of these notes will be filed directly under an existing project, some will be split in several subtasks and some others will lead to the creation of a new project.

Summary

Our first (incomplete) GTD configuration is:

GTD.el (version 1)
(require 'org)

(setq org-directory "~/Documents/org")
(setq org-agenda-files (list "inbox.org"))

(setq org-capture-templates
      `(("i" "Inbox" entry  (file "inbox.org")
        ,(concat "* TODO %?\n"
                 "/Entered on/ %U"))
        ("@" "Inbox [mu4e]" entry (file "inbox.org")
        ,(concat "* TODO Reply to \"%a\" %?\n"
                 "/Entered on/ %U"))))

(defun org-capture-inbox ()
     (interactive)
     (call-interactively 'org-store-link)
     (org-capture nil "i"))

(defun org-capture-mail ()
  (interactive)
  (call-interactively 'org-store-link)
  (org-capture nil "@"))

;; Use full window for org-capture
(add-hook 'org-capture-mode-hook 'delete-other-windows)

(define-key global-map            (kbd "C-c c") 'org-capture)
(define-key global-map            (kbd "C-c i") 'org-capture-inbox)

;; Only if you use mu4e
;; (require 'mu4e)
;; (define-key mu4e-headers-mode-map (kbd "C-c i") 'org-capture-mail)
;; (define-key mu4e-view-mode-map    (kbd "C-c i") 'org-capture-mail)

The set of available commands at this point is:

CommandBindingsMode + where
Capture menuC-c cany
Capture a new TODOC-c i or C-c c iany
Capture a mail-related TODOC-c i or C-c c @mu4e view/headers mode

Agenda

Basic setup (I)

Before heading to the review process, we need first to setup the agenda that will help us to track daily meetings and tasks. Using the previous inbox configuration, you can actually already have a view of your inbox using the M-x org-agenda command that will bring up a menu where you can choose what to display. Before using it, let me first define a new global key binding (C-c a) for quick access to the agenda:

(define-key global-map (kbd "C-c a") 'org-agenda)

Now, letā€™s see what our tasks look like by invoking the ā€œList of All TODO entriesā€ using the t menu (full sequence is thus C-c a t):

*Global list of TODO items of type: ALL*
*Press ā€˜N rā€™ (e.g. ā€˜0 rā€™) to search again: (0)[ALL] (1)TODO (2)DONE*
  inbox:      TODO Organize bibliography                                     /:inbox:/
  inbox:      TODO Process "Adaptive Computation Timeā€¦"                      /:inbox:/
  inbox:      TODO Process "Relevant paper"                                  /:inbox:/
  inbox:      TODO Mail F.Wagner about team talk                             /:inbox:/
  inbox:      TODO Buy "Canon printer"                                       /:inbox:/
  inbox:      TODO Process "ICDL oral presentation"                          /:inbox:/
  inbox:      TODO Write discution (plasticity paper)                        /:inbox:/
  inbox:      TODO Compute VSOM Ī“xĪ“y representation                          /:inbox:/

The display of the task list is bit redundant because we have an ā€œinboxā€ on the left and an ā€œinboxā€ on the right. However, they do not have the same origin. The one on the left is the name of the file where the related TODO is stored while the one on the right is a tag. If you remember our inbox file setup header, there was a #+FILETAGS: inbox line that assign the ā€œinboxā€ tag to each entry. Since tags are redundant, letā€™s just remove them by filtering them out:

(setq org-agenda-hide-tags-regexp ".")

With this line, we actually ask the agenda to hide any tag (.) that may be present. Of course, you can choose to be more specific and hide only some tags, itā€™s up to you. Now we still have to choose what to do with the left part displaying ā€œinboxā€. This is displayed because there is no category assigned to the entry and when the agenda display a TODO item, the default behavior is to display the category or the filename if there is no category. You can of course change what is actually displayed by modifying the org-agenda-prefix-format:

(setq org-agenda-prefix-format
      '((agenda . " %i %-12:c%?-12t% s")
        (todo   . " %i %-12:c")
        (tags   . " %i %-12:c")
        (search . " %i %-12:c")))

We could also add a #+CATEGORY: INBOX to the header of our inbox file but I prefer not to have anything displayed for now. So letā€™s getā€™s rid of the category display for todo items:

(setq org-agenda-prefix-format
      '((agenda . " %i %-12:c%?-12t% s")
        (todo   . " ")
        (tags   . " %i %-12:c")
        (search . " %i %-12:c")))

And the result is:

*Global list of TODO items of type: ALL*
*Press ā€˜N rā€™ (e.g. ā€˜0 rā€™) to search again: (0)[ALL] (1)TODO (2)DONE*
  TODO Organize bibliography
  TODO Process "Adaptive Computation Timeā€¦"
  TODO Process "Relevant paper"
  TODO Mail F.Wagner about team talk
  TODO Buy "Canon printer"
  TODO Process "ICDL oral presentation"
  TODO Write discution (plasticity paper)
  TODO Compute VSOM Ī“xĪ“y representation

Recurrent events

Beside notes taking, I send or received a number of appointments (generally through mail) and I need to save them. I prefer not to file them in my inbox since generally I know both the topic and when they will occur such that I can directly store them in a dedicated agenda.org file that will be used to store all my scheduled events and meetings. Letā€™s first add this new file to the list of org files:

(setq org-agenda-files (list "inbox.org" "agenda.org"))

The initial file has a basic startup header configuration and I also defined a set of default tags using the #+TAGS syntax. This will ease the assignment of tags when adding a new entry or modifying an entry (weā€™ll see that later):

#+STARTUP: hideall showstars indent
#+TAGS:    event(e) meeting(m) deadline(d)
#+TAGS:    @outside(o) @imn(i) @inria(r) @online(l) @canceled(c)

The structure of my agenda is split into birthdays and recurrent / past / future events. This quite arbitrary and you can use any a different structure.

* *Birthdays*
* *Recurrent*
  * *Scheduled*
  * *People*
  * *Team*
* *Past*
* *Future*

Letā€™s first start filling the birthdays part. For any yearly event such as birthdays, we can add special entries using the org-anniversary syntax (from the diary).

* *Birthdays*
  %%(org-anniversary 1976 6  1) Emacs is %d years old
  %%(org-anniversary 1953 3 16) Richard Stallman is %d years old

Each time month/day is displayed in the agenda, the corresponding text will be displayed as well.

For the recurrent events, I make a separation between scheduled, people and team. In my case, scheduled events are mostly daily events and I use the agenda as a reminder. I could have used the repeating tasks feature (using syntax such as [2020-09-12 Sat 09:00 +1d], but the problem is that I wanted to have some daily repeating task only for workdays and the previous syntax does not offer such choice. Instead, Iā€™ve used the following code:

* *Recurrent*
  * *Scheduled*
    * *GTD Review* 18:00-18:20                                          /:review:@home:/
      /SCHEDULED: <%%(memq (calendar-day-of-week date) '(1 2 3 4 5))>/
    * *Notes cleaning* 18:20-18:30                                      /:review:@home:/
      /SCHEDULED: <%%(memq (calendar-day-of-week date) '(1 2 3 4 5))>/
    * *Agenda cleaning*                                                 /:review:@home:/
      /SCHEDULED: <2020-09-01 Tue +1m>/

For recurrent events with people, I do not use the repeating task feature because I want to be able to cancel a specific meeting if it did not happen and also to use the entry for taking notes (we will see that below).

* *Recurrent*
  * *People*
    * *Student A (weekly meeting)*                                           /:meeting:/
      * *Student A*                                                        /:@canceled:/
        /<2020-09-14 Mon 10:00-11:00>/
      * *Student A*                                                          /:@online:/
        /<2020-09-07 Mon 10:00-11:00>/
      * *Student A*                                                             /:@imn:/
        /<2020-09-14 Mon 10:00-11:00>/

For these recurrent events, I write them directly into the agenda file at the end of a meeting where we generally agree on next meeting. Here is quick reminder by Greg Lucas on how to enter date and their definition:

PLAIN timestamp (C-c .)
This is used for things like appointments where the entry occurs at a specific date/time. Such an entry will show up in the agenda on the specified day, and will not show up after that day has passed. Note that an appointment in the past wonā€™t keep showing up on your agenda regardless of whether you mark it DONE: if you didnā€™t go to your doctorā€™s appointment yesterday, that doesnā€™t mean you still have one today!
SCHEDULED timestamp (C-c C-s)
This is used to indicate when you intend to do the task. It will show up on the agenda on the scheduled day. If you donā€™t complete the task at that time, it will continue to show up on the agenda on the following days to show you that you have not completed something that you planned to do.
DEADLINE timestamp (C-c C-d)
This is used to indicate when something must be completed. Typically you want to see deadlines ahead of time, so that you can do whatever it is that must be done to meet them. Like a scheduled entry, if you miss a deadline it will continue to appear on the agenda as past due.
INACTIVE timestamp (C-c !)
This is when you want to attach a date to an entry but do not want it to show up in the agenda at all. Inactive timestamps have no special behavior.

Meetings & notes

Now it is time to define a new capture template for registering a meeting.

("m" "Meeting" entry  (file+headline "agenda.org" "Future")
 ,(concat "* %? :meeting:\n"
         "<%<%Y-%m-%d %a %H:00>>"))

It is not very complicated: any meeting will be filed in agenda.org under the Future header (and will be refiled later, during agenda review). By default, the timestamp is the current day with a rounded clock since my meetings generally starts at plain hours. When invoked, this template looks like:

*Capture buffer. Finish 'C-c C-c', refile 'C-c C-w', abort 'C-c C-k'.*
* +_+                                                                        /:meeting:/
  /<2020-09-11 Fri 11:00>/

When I enter a meeting, I generally use the name of people that will be present at the meeting (if there are not too many people) or the topic of the meeting. The goal is to have short but useful information when the meeting shows up in my agenda.

The next step is to define a ā€œNoteā€ template that will be used to take notes during a meeting:

("n" "Note" entry  (file "notes.org")
 ,(concat "* Note (%a)\n"
         "/Entered on/ %U\n" "\n" "%?"))

We will (temporarily) store these notes in a notes.org dedicated file. Maybe youā€™ve noticed the ā€%aā€, in the template. This is a template extension that will be resolved to the content created with the org-store-link command. However, if you capture a note while your cursor is on the same line of an agenda entry, the content will be filled with this entry. This is super convenient to link your note with the agenda entry.

My initial notes.org is as follows:

#+STARTUP: content showstars indent
#+FILETAGS: notes

Nothing fancy here since it is actually a temporary storage, notes will be later moved to the relevant project they belong to.

Summary

Here is our updated configuration:

GTD.el (version 2)
(require 'org)

(setq org-directory "~/Documents/org")
(setq org-agenda-files (list "inbox.org" "agenda.org" "notes.org"))

(setq org-capture-templates
      `(("i" "Inbox" entry  (file "inbox.org")
        ,(concat "* TODO %?\n"
                 "/Entered on/ %U"))
        ("m" "Meeting" entry  (file+headline "agenda.org" "Future")
        ,(concat "* %? :meeting:\n"
                 "<%<%Y-%m-%d %a %H:00>>"))
        ("n" "Note" entry  (file "notes.org")
        ,(concat "* Note (%a)\n"
                 "/Entered on/ %U\n" "\n" "%?"))
        ("@" "Inbox [mu4e]" entry (file "inbox.org")
        ,(concat "* TODO Reply to \"%a\" %?\n"
                 "/Entered on/ %U"))))

(defun org-capture-inbox ()
     (interactive)
     (call-interactively 'org-store-link)
     (org-capture nil "i"))

(defun org-capture-mail ()
  (interactive)
  (call-interactively 'org-store-link)
  (org-capture nil "@"))

;; Use full window for org-capture
(add-hook 'org-capture-mode-hook 'delete-other-windows)

(define-key global-map            (kbd "C-c a") 'org-agenda)
(define-key global-map            (kbd "C-c c") 'org-capture)
(define-key global-map            (kbd "C-c i") 'org-capture-inbox)

;; Only if you use mu4e
;; (require 'mu4e)
;; (define-key mu4e-headers-mode-map (kbd "C-c i") 'org-capture-mail)
;; (define-key mu4e-view-mode-map    (kbd "C-c i") 'org-capture-mail)

The set of available commands is now:

CommandBindingsMode + where
AgendaC-c aany
Agenda for todayC-c a aany
Capture menuC-c cany
Capture meeting (agenda.org)C-c c many
Capture meeting note (notes.org)C-c c nany
Capture generic TODO (inbox.org)C-c i or C-c c iany
Capture mail TODO (inbox.org)C-c i or C-c c @mu4e view/headers mode
Add/Remove tagC-c C-corg-mode on headline
Plain timestampC-c .org-mode
Scheduled timestampC-c C-sorg-mode
Deadline timestampC-c C-dorg-mode
Inactive timestampC-c !org-mode

Review

The actual review process is probably the less documented aspect of GTD from all the resources Iā€™ve read so far. When it is mentioned, some people explain they have a weekly review while some others uses a daily review. To get things further complicated, it is not clear if this process is a matter of a few minutes or a matter of hours. My personal point of view so far (and this may change in the future) is that a daily process is probably the way to go in my case since Iā€™m adding from 5 to 10 entries to my inbox each day (mail included). For me, the end of the work day seems to be the best time to do the review since my memory is still fresh with things Iā€™ve done during the day, and what may come next for each project.

Basic setup

My review process consists mostly in moving things out of the inbox in order to file them in the corresponding project if it exists or to create one if this is not the case. To do that, we need first to create a new projects.org file that will hold all our projects. The structure of this file is quite important because youā€™ll interact with it a lot of times. I chose to split first my projects into global categories:

#+STARTUP: content showstars indent
* *Students*                                                                /:students:/
* *Team*                                                                        /:team:/
* *Collaboratorive projects*                                   /:collaborative:project:/
* *Events organization*                                                       /:events:/
* *Academic papers*                                                          /:article:/
* *Personal projects*                                               /:personal:project:/
* *ReScience*                                                              /:rescience:/
* *Home*                                                                        /:home:/

I then add projects under one of these categories using a specific structure. Let me show you a typical student ā€œprojectā€:

* *Students*                                                                /:students:/
  * *J.Doe (PhD)* [/]                                                      /:phd:j.doe:/
    /:PROPERTIES:/
    /:CATEGORY: J.DOE/
    /:VISIBILITY: hide/
    /:COOKIE_DATA: recursive todo/
    /:END:/
    * *Information*                                                             /:info:/
      /:PROPERTIES:/
      /:VISIBILITY: hide/
      /:END:/
    * *Notes*                                                                  /:notes:/
      /:PROPERTIES:/
      /:VISIBILITY: hide/
      /:END:/
    * *Tasks*                                                                  /:tasks:/
      /:PROPERTIES:/
      /:VISIBILITY: content/
      /:END:/

The information section contains information related to the project and youā€™re free to organize the way you want. The notes section is where I move meeting notes related to this project during my notes review. Finally, the tasks is where I will move related inbox entries. I also set different visibility properties for each section: information and notes are hidden while tasks section is open. You might have also noticed the COOKIE_DATA property at the top and the [/] at the end of the project name. These two components will help us to track the number of pending tasks vs the number of completed tasks. Each time weā€™ll move a task from the TODO state to the DONE state, the header will be updated accordingly (you can also refresh it with C-c C-c when the cursor is over it).

The overall number of projects is very dependent on you. In my case, Iā€™ve about 40 opened projects. Some will last a few months (e.g. academic papers), some will last a few years (e.g. grants and phd students) and some others do not have foreseeable end (house, garden, car).

Moving things

Before refiling inbox entries into projects, I usually try to set an estimated time (effort) needed to complete the tasks as well as some contextual information (using tags). To ease the process, weā€™ll first modify the inbox header to add typical estimated efforts and some tags that will speed the overall processing of each entry.

#+STARTUP: content showstars indent
#+TAGS: @home(h) @work(w) @mail(m) @comp(c) @web(b) 
#+PROPERTY: Effort_ALL 0 0:05 0:10 0:15 0:30 0:45 1:00 2:00 4:00

Before refiling (i.e. moving) an entry, I will set some tags using the C-c C-c keybinding and if the entry is an atomic task (i.e. that can be done independently of any others tasks), Iā€™ll assign an estimated effort using the existing C-c C-x e key binding. For example, letā€™s consider the following entry before review:

* TODO Write review section (GTD.org)
  /Entered on [2020-09-12 Sat 09:20]/

After having set effort and tags, the entry reads:

* TODO Write review section (GTD.org)                                        :@comp:
  /:PROPERTIES:/
  /:Effort:   0:30/
  /:END:/
  /Entered on [2020-09-12 Sat 09:20]/

Tags are supposed to give some contextual information on where the task can be completed. However, I did not really use them partly due to the 2020 sanitary crisis that tends to blur the line between work and home. Setting the estimated is however quite important for me because when Iā€™ll activate a task, the estimated effort will be displayed in the agenda and will help me to decide if I can engage in task depending on the amount of free time I have. This is especially useful for small tasks (5 minutes) that can be completed any time.

Now itā€™s time to move the entry.

I explained that inbox entries have to be moved into the relevant project under the Tasks headline. To do that, weā€™ll use the org-refile function (bound to C-c C-w when on a headline) and specify where the entry can be refiled in the projects.org. If you remember, we also have notes that needs to be refiled in projects such that targets in projects.org are either Notes or Tasks. We thus need to define a refile target using regexp. One easy way to do that is to use the regexp-opt function:

(regexp-opt '("Tasks" "Notes"))

You can evaluate the expression by placing the cursor at the end of the line and type C-u C-x C-e. The optimized regex (~ā€\(?:\(?:Note\|Task\)s\)ā€~) should appear at the end of the line. We can now use it so specifiy our targets:

(setq org-refile-targets
      '(("projects.org" :regexp . "\\(?:\\(?:Note\\|Task\\)s\\)")))

Last step is to tell org-mode we want to specify a refile target using the file path.

(setq org-refile-use-outline-path 'file)
(setq org-outline-path-complete-in-steps nil)

To refile a J.Doe related inbox entry, you can then type:

C-c C-w + "J.Doe" + tab + "T" + tab

and this will be resolved to =ā€projects.org/Students/J.Doe/Tasksā€=.

Activating tasks

After having emptied the inbox, itā€™s time to have a look at the different projects to decide what are the next tasks to be activated. Before doing that, we need to define what is an active task. Org-mode defines two different states for TODO items: TODO and DONE. We need to modify this in order to introduce two new non-terminal state: NEXT to express this is the next task to be completed and HOLD to express this task is on hold (for whaterver reason):

(setq org-todo-keywords
      '((sequence "TODO(t)" "NEXT(n)" "HOLD(h)" "|" "DONE(d)")))

Thanks to Erik Anderson, we can also add a hook that will log when we activate a task by creating an ā€œACTIVATEDā€ property the first time the task enters the NEXT state:

(defun log-todo-next-creation-date (&rest ignore)
  "Log NEXT creation time in the property drawer under the key 'ACTIVATED'"
  (when (and (string= (org-get-todo-state) "NEXT")
             (not (org-entry-get nil "ACTIVATED")))
    (org-entry-put nil "ACTIVATED" (format-time-string "[%Y-%m-%d]"))))
(add-hook 'org-after-todo-state-change-hook #'log-todo-next-creation-date)

Weā€™ll see in the next section how to exploit this property. Next step is to update the trailing [/] behind each headline. To do that, you can type C-u C-c #. For each projects, you now have something like [x/y] where x is the number of closed tasks and y is the total number of tasks. Any project with x < y means that there are some tasks that can be activated. You can now selectively open a project and decide if you want to activate one of the non closed task. The most easy way to do that is to go over the TODO keyword and use S-right to advance to the NEXT state.

Summary

Here is our updated configuration:

GTD.el (version 3)
(require 'org)

;; Files
(setq org-directory "~/Documents/org")
(setq org-agenda-files (list "inbox.org" "agenda.org" "notes.org"))

;; Capture
(setq org-capture-templates
      `(("i" "Inbox" entry  (file "inbox.org")
        ,(concat "* TODO %?\n"
                 "/Entered on/ %U"))
        ("m" "Meeting" entry  (file+headline "agenda.org" "Future")
        ,(concat "* %? :meeting:\n"
                 "<%<%Y-%m-%d %a %H:00>>"))
        ("n" "Note" entry  (file "notes.org")
        ,(concat "* Note (%a)\n"
                 "/Entered on/ %U\n" "\n" "%?"))
        ("@" "Inbox [mu4e]" entry (file "inbox.org")
        ,(concat "* TODO Reply to \"%a\" %?\n"
                 "/Entered on/ %U"))))

(defun org-capture-inbox ()
     (interactive)
     (call-interactively 'org-store-link)
     (org-capture nil "i"))

(defun org-capture-mail ()
  (interactive)
  (call-interactively 'org-store-link)
  (org-capture nil "@"))

;; Use full window for org-capture
(add-hook 'org-capture-mode-hook 'delete-other-windows)

;; Key bindings
(define-key global-map            (kbd "C-c a") 'org-agenda)
(define-key global-map            (kbd "C-c c") 'org-capture)
(define-key global-map            (kbd "C-c i") 'org-capture-inbox)

;; Only if you use mu4e
;; (require 'mu4e)
;; (define-key mu4e-headers-mode-map (kbd "C-c i") 'org-capture-mail)
;; (define-key mu4e-view-mode-map    (kbd "C-c i") 'org-capture-mail)

;; Refile
(setq org-refile-use-outline-path 'file)
(setq org-outline-path-complete-in-steps nil)
(setq org-refile-targets
      '(("projects.org" :regexp . "\\(?:\\(?:Note\\|Task\\)s\\)")))

;; TODO
(setq org-todo-keywords
      '((sequence "TODO(t)" "NEXT(n)" "HOLD(h)" "|" "DONE(d)")))
(defun log-todo-next-creation-date (&rest ignore)
  "Log NEXT creation time in the property drawer under the key 'ACTIVATED'"
  (when (and (string= (org-get-todo-state) "NEXT")
             (not (org-entry-get nil "ACTIVATED")))
    (org-entry-put nil "ACTIVATED" (format-time-string "[%Y-%m-%d]"))))
(add-hook 'org-after-todo-state-change-hook #'log-todo-next-creation-date)

The set of available commands is now:

CommandBindingsMode + where
AgendaC-c aany
Agenda for todayC-c a aany
Capture menuC-c cany
Capture meeting (agenda.org)C-c c many
Capture meeting note (notes.org)C-c c nany
Capture generic TODO (inbox.org)C-c i or C-c c iany
Capture mail TODO (inbox.org)C-c i or C-c c @mu4e view/headers mode
Add/Remove tagC-c C-corg-mode on headline
Update progress indicatorC-c C-corg-mode on [/]
Update all progress indicatorsC-u C-c #org-mode
Enter estimated effortC-c C-x eorg-mode on headline
Refile sectionC-c C-worg-mode on headline
Move to next TODO stateS-rightorg-mode on TODO
Plain timestampC-c .org-mode
Scheduled timestampC-c sorg-mode
Deadline timestampC-c dorg-mode
Inactive timestampC-c !org-mode

Doing things

Agenda setup (II)

Itā€™s now time to work on custom agenda view that will display meetings for the day, task that need to be done and deadlines. Weā€™ll also add the content of the inbox as a reminder to file entries, and the tasks weā€™ve completed today. So overall, our custom agenda headers will be:

*Day-agenda (W37):* ā€¦
*Sunday 13 September 2020* ā€¦
*Tasks* ā€¦
*Deadlines* ā€¦
*Inbox* ā€¦
*Completed today* ā€¦

Letā€™s write a new agenda customn command (g) using the org-custom-agenda-commands variable.

(setq org-agenda-custom-commands
      '(("g" "Get Things Done (GTD)"
         ((agenda ""
                  ((org-agenda-skip-function
                    '(org-agenda-skip-entry-if 'deadline))
                   (org-deadline-warning-days 0)))
          (todo "NEXT"
                ((org-agenda-skip-function
                  '(org-agenda-skip-entry-if 'deadline))
                 (org-agenda-prefix-format "  %i %-12:c [%e] ")
                 (org-agenda-overriding-header "\nTasks\n")))
          (agenda nil
                  ((org-agenda-entry-types '(:deadline))
                   (org-agenda-format-date "")
                   (org-deadline-warning-days 7)
                   (org-agenda-skip-function
                    '(org-agenda-skip-entry-if 'notregexp "\\* NEXT"))
                   (org-agenda-overriding-header "\nDeadlines")))
          (tags-todo "inbox"
                     ((org-agenda-prefix-format "  %?-12t% s")
                      (org-agenda-overriding-header "\nInbox\n")))
          (tags "CLOSED>=\"<today>\""
                ((org-agenda-overriding-header "\nCompleted today\n")))))))

I wonā€™t detail every line because youā€™ll find a lot of information online, in the documentation and inside emacs as well.

Agenda view (2020-09-13)
*Day-agenda (W37):*

*Sunday 13 September 2020*

   8:00......   ----------------
   8:45- 9:00   Scheduled:  Keyboard training 
  10:00......   ----------------
  12:00......   ----------------
  14:00......   ----------------
  *14:19......*   *> now <*
  16:00......   ----------------
  18:00......   ----------------
  20:00......   ----------------
  Sched.12x:  Agenda cleaning

*Tasks*

   VIZBOOK:       [0:30] NEXT Organize book writing          (4d.)
   RESCIENCE-X:   [0:30] NEXT ReScience X DOI registrar      (4d.)
   DNFSOM:        [0:20] NEXT [#A] Read section 4 on DNFSOM  (2d.)
   X.YYYYY:       [0:05] NEXT Mail X.Yyyyy (PhD)             (1d.)

*Deadlines*

   3 d. ago:  NEXT [#A] Read /"Chapitre RNN 2020-09-08"/       (4d.)
   3 d. ago:  NEXT [#A] Read /"Chapitre WMEXP 2020-09-08]]"/   (4d.)

*Inbox*

  TODO Organize bibliography
  TODO Read to /"Adaptive Computation Time for Recurrent Neural Networks"/
  TODO Process /"Relevant paper"/
  TODO Mail X.Yyyyy about team talk
  TODO Buy /"Canon printer"/
  TODO Process /"ICDL oral presentation"/
  TODO Write discution (plasticity paper)
  TODO Compute VSOM Ī“xĪ“y representation
  TODO Process /"Internships for Students at Ecole Polytechnique"/

*Completed today*
 
  DONE Write GTD Review section

You can see that entries in the Task section display a duration in front of the description. May youā€™ve guessed that this duration corresponds to the estimated effort we entered during the review process. Now, each time you have some free time ahead, you can which task you want to engage based on this estimation. Very convenient.

Completing a task

Once youā€™ve chosen a task to do, and before starting the task, you can choose to log the time it will actually take to complete the task such that you can later refine your estimation. Just type C-c C-x C-i (clock in) to start the clock and C-c C-x C-o (clock out) to stop the clock and to add the duration in the logbook. Once a task is completed, you can change its state from NEXT to DONE (using S-right while the cursor is over the NEXT word). In order to keep track of when the task was completed, we can ask org-mode to log that:

(setq org-log-done 'time)

This will add a CLOSED: [2020-09-13 Sun 19:24] line under the corresponding entry. Using this time, we can thus display the tasks that have been completed during the day (see the last line of our agenda custom commands).

To summarize, for a given task:

* TODO Some task
  /Entered on [2020-09-13 Sun 19:23]/

It will be first modified be when the estimated effort is set:

* TODO Some task
  /:PROPERTIES:/
  /:EFFORT: 0:30/
  /:END:/
  /Entered on [2020-09-13 Sun 19:23]/

and further modified when activated:

* NEXT Some task
  /:PROPERTIES:/
  /:EFFORT: 0:30/
  /:ACTIVATED: [2020-09-13 Sun]/
  /:END:/
  /Entered on [2020-09-13 Sun 19:23]/

Finally, once completed, we have:

* DONE Some task
  /CLOSED: [2020-09-13 Sun 20:14]/
  /:PROPERTIES:/
  /:EFFORT: 0:30/
  /:ACTIVATED: [2020-08-30]/
  /:END:/
  /:LOGBOOK:/
  /CLOCK: [2020-09-13 Sun 19:55]--[2020-09-13 Sun 20:14] => 0:19/
  /:END:/
  /Entered on [2020-09-13 Sun 19:23]/

Next time we have to estimate the effort for this specific task, and based on the above log, weā€™ll probably set it to 20 minutes instead of 30.

Summary

Our final configuration is thus

GTD.el (version 4)
(require 'org)

;; Files
(setq org-directory "~/Documents/org")
(setq org-agenda-files (list "inbox.org" "agenda.org"
                             "notes.org" "projects.org"))

;; Capture
(setq org-capture-templates
      `(("i" "Inbox" entry  (file "inbox.org")
        ,(concat "* TODO %?\n"
                 "/Entered on/ %U"))
        ("m" "Meeting" entry  (file+headline "agenda.org" "Future")
        ,(concat "* %? :meeting:\n"
                 "<%<%Y-%m-%d %a %H:00>>"))
        ("n" "Note" entry  (file "notes.org")
        ,(concat "* Note (%a)\n"
                 "/Entered on/ %U\n" "\n" "%?"))
        ("@" "Inbox [mu4e]" entry (file "inbox.org")
        ,(concat "* TODO Reply to \"%a\" %?\n"
                 "/Entered on/ %U"))))

(defun org-capture-inbox ()
     (interactive)
     (call-interactively 'org-store-link)
     (org-capture nil "i"))

(defun org-capture-mail ()
  (interactive)
  (call-interactively 'org-store-link)
  (org-capture nil "@"))

;; Use full window for org-capture
(add-hook 'org-capture-mode-hook 'delete-other-windows)

;; Key bindings
(define-key global-map            (kbd "C-c a") 'org-agenda)
(define-key global-map            (kbd "C-c c") 'org-capture)
(define-key global-map            (kbd "C-c i") 'org-capture-inbox)

;; Only if you use mu4e
;; (require 'mu4e)
;; (define-key mu4e-headers-mode-map (kbd "C-c i") 'org-capture-mail)
;; (define-key mu4e-view-mode-map    (kbd "C-c i") 'org-capture-mail)

;; Refile
(setq org-refile-use-outline-path 'file)
(setq org-outline-path-complete-in-steps nil)
(setq org-refile-targets
      '(("projects.org" :regexp . "\\(?:\\(?:Note\\|Task\\)s\\)")))

;; TODO
(setq org-todo-keywords
      '((sequence "TODO(t)" "NEXT(n)" "HOLD(h)" "|" "DONE(d)")))
(defun log-todo-next-creation-date (&rest ignore)
  "Log NEXT creation time in the property drawer under the key 'ACTIVATED'"
  (when (and (string= (org-get-todo-state) "NEXT")
             (not (org-entry-get nil "ACTIVATED")))
    (org-entry-put nil "ACTIVATED" (format-time-string "[%Y-%m-%d]"))))
(add-hook 'org-after-todo-state-change-hook #'log-todo-next-creation-date)

;; Agenda
(setq org-agenda-custom-commands
      '(("g" "Get Things Done (GTD)"
         ((agenda ""
                  ((org-agenda-skip-function
                    '(org-agenda-skip-entry-if 'deadline))
                   (org-deadline-warning-days 0)))
          (todo "NEXT"
                ((org-agenda-skip-function
                  '(org-agenda-skip-entry-if 'deadline))
                 (org-agenda-prefix-format "  %i %-12:c [%e] ")
                 (org-agenda-overriding-header "\nTasks\n")))
          (agenda nil
                  ((org-agenda-entry-types '(:deadline))
                   (org-agenda-format-date "")
                   (org-deadline-warning-days 7)
                   (org-agenda-skip-function
                    '(org-agenda-skip-entry-if 'notregexp "\\* NEXT"))
                   (org-agenda-overriding-header "\nDeadlines")))
          (tags-todo "inbox"
                     ((org-agenda-prefix-format "  %?-12t% s")
                      (org-agenda-overriding-header "\nInbox\n")))
          (tags "CLOSED>=\"<today>\""
                ((org-agenda-overriding-header "\nCompleted today\n")))))))

The set of available commands is now:

CommandBindingsMode + where
AgendaC-c aany
Agenda for todayC-c a aany
Capture menuC-c cany
Capture meeting (agenda.org)C-c c many
Capture meeting note (notes.org)C-c c nany
Capture generic TODO (inbox.org)C-c i or C-c c iany
Capture mail TODO (inbox.org)C-c i or C-c c @mu4e view/headers mode
Add/Remove tagC-c C-corg-mode on headline
Update progress indicatorC-c C-corg-mode on [/]
Update all progress indicatorsC-u C-c #org-mode
Enter estimated effortC-c C-x eorg-mode on headline
Refile sectionC-c C-worg-mode on headline
Move to next TODO stateS-rightorg-mode on TODO
Clock inC-c C-x C-iorg-mode on headline
Clock outC-c C-x C-oorg-mode on headline
Plain timestampC-c .org-mode
Scheduled timestampC-c sorg-mode
Deadline timestampC-c dorg-mode
Inactive timestampC-c !org-mode

Additional changes

Automatic saving after refilling

After refilling, you will have to save manually your opened org files, which is not really convenient. Fortunately, a small change in the code will save the files automatically.

First, you need to get the files you want to save with their fullpath. Replace the previous definition of org-agenda-files with the following:

(setq org-agenda-files 
      (mapcar 'file-truename 
	      (file-expand-wildcards "~/Documents/org/*.org")))

Now, we create a new function to save those files, using the model of the org-save-all-org-buffers function and finally we add it after the org-refile action:

;; Save the corresponding buffers
(defun gtd-save-org-buffers ()
  "Save `org-agenda-files' buffers without user confirmation.
See also `org-save-all-org-buffers'"
  (interactive)
  (message "Saving org-agenda-files buffers...")
  (save-some-buffers t (lambda () 
			 (when (member (buffer-file-name) org-agenda-files) 
			   t)))
  (message "Saving org-agenda-files buffers... done"))

;; Add it after refile
(advice-add 'org-refile :after
	    (lambda (&rest _)
	      (gtd-save-org-buffers)))

Conclusion

Iā€™m now done describing my GTD setup and I hope it will be useful for some readers. Iā€™m rather new to GTD and there are certainly better ways to implement GTD (see *Resources) and probably Iā€™ll modify some parts in the future.

If you spot errors or typos, feel free to open an issue at https://github.com/rougier/emacs-GTD.

Going further

As explained in the introduction, there are plenty of resources online regarding org-mode in general and GTD with org-mode in particular. There are also plenty of interactive places where you ask for help and find some code:

Local Variables

More Repositories

1

numpy-100

100 numpy exercises (with solutions)
Python
10,706
star
2

scientific-visualization-book

An open access book on scientific visualization using python and matplotlib
Python
10,697
star
3

matplotlib-cheatsheet

Matplotlib 3.1 cheat sheet.
Python
2,898
star
4

matplotlib-tutorial

Matplotlib tutorial for beginner
Python
2,776
star
5

nano-emacs

GNU Emacs / N Ī› N O - Emacs made simple
Emacs Lisp
2,564
star
6

from-python-to-numpy

An open-access book on numpy vectorization techniques, Nicolas P. Rougier, 2017
Python
1,904
star
7

freetype-gl

OpenGL text using one vertex buffer, one texture and FreeType
C
1,641
star
8

elegant-emacs

A very minimal but elegant emacs (I think)
Emacs Lisp
1,368
star
9

CPP-Crash-Course

C++ Crash Course
C++
716
star
10

ML-Recipes

A collection of stand-alone Python machine learning recipes
Python
657
star
11

notebook-mode

GNU Emacs notebook mode
Emacs Lisp
617
star
12

python-opengl

An open access book on Python, OpenGL and Scientific Visualization, Nicolas P. Rougier, 2018
HTML
575
star
13

svg-tag-mode

A minor mode for Emacs that replace keywords with nice SVG labels
Emacs Lisp
496
star
14

mu4e-dashboard

A dashboard for mu4e (mu for emacs)
Emacs Lisp
465
star
15

numpy-tutorial

Numpy beginner tutorial
Python
459
star
16

nano-theme

GNU Emacs / N Ī› N O Theme
Emacs Lisp
374
star
17

svg-lib

Emacs SVG libraries for creatings tags, icons and bars
Emacs Lisp
340
star
18

book-mode

A clean interface for org files (Emacs)
Emacs Lisp
290
star
19

ten-rules

Ten simple rules for better figures
Python
274
star
20

freetype-py

Python binding for the freetype library
Python
270
star
21

matplotlib-3d

Experimental 3D axis for matplotlib
Python
269
star
22

dotemacs

Litterate configuration for GNU Emacs
216
star
23

nano-modeline

GNU Emacs / N Ī› N O Modeline
Emacs Lisp
175
star
24

tiny-renderer

A tiny sotfware 3D renderer in 100 lines of Python
Python
171
star
25

org-bib-mode

An Emacs minor mode for literate & annotated bibliography
Emacs Lisp
136
star
26

mu4e-thread-folding

Functions for folding threads in mu4e headers view
Emacs Lisp
136
star
27

agenda

Org agenda in the console
Python
134
star
28

neural-networks

Artificial Neural Networks / Python
Python
134
star
29

nano-sidebar

Emacs package to have configurable sidebars on a per frame basis.
Emacs Lisp
128
star
30

notes-list

Emacs notes list
Emacs Lisp
102
star
31

scipy-crash-course

Material for a 24 hours course on Scientific Python
102
star
32

python-visualization-landscape

Adaptation of Jake VanderPlas graphic about python visualization landscape
HTML
97
star
33

org-margin

Outdent headlines in emacs org-mode
Emacs Lisp
96
star
34

calendar-heatmap

Calendar heatmap with matplotlib and random data
Python
95
star
35

emacs-svg-icon

An emacs library to create SVG icons on the fly
Emacs Lisp
94
star
36

sideframe

Emacs side frames
Emacs Lisp
88
star
37

nano-dialog

Emac native dialog box
Emacs Lisp
87
star
38

nano-agenda

A minimal org agenda for Emacs
Emacs Lisp
84
star
39

gl-agg

OpenGL Antigrain Geometry experiments
Python
83
star
40

nano-elfeed

Emacs configuration file for elfeed (news reader)
Emacs Lisp
68
star
41

emacs-splash

An alternative splash screen for GNU Emacs
Emacs Lisp
63
star
42

recursive-voronoi

Recursive voronoi diagram
Python
60
star
43

2021-Dataviz

Material for dataviz course at university of Bordeaux
Jupyter Notebook
51
star
44

CNCC-2020

Computational Neuroscience Crash Course (University of Bordeaux, 2020)
Jupyter Notebook
48
star
45

gallery

Gallery of matplotlib samples
Python
47
star
46

50-git-questions

50 Frequently Asked question about Git & GitHub
47
star
47

mastodon-alt

Emacs alternative mastodon layout
Emacs Lisp
46
star
48

baby-gnu-tux

3D files for printing baby GNU and Tux
46
star
49

windmap

Streamlines animation (matplotlib)
Python
46
star
50

URFIST-git-course

This is the material for the URFIST course on Git & GitHub. Bordeaux, March 27 & 28, 2018.
44
star
51

rougier

Exended profile
43
star
52

nano-vertico

Emacs / nano + vertico
Emacs Lisp
43
star
53

minibuffer-header

Minibuffer header for GNU/Emacs
Emacs Lisp
43
star
54

open-heroes

Some people that facilitate science, one way or the other
41
star
55

alien-life

Remake of necessary disorrder beautiful animation
Python
41
star
56

reviewer-manifesto

A pledge for reviewers
40
star
57

pyglfw

Python bindings for GLFW 3.0
Python
40
star
58

pdf-drop-mode

Get DOI from PDF files dropped onto a Emacs buffer
Emacs Lisp
35
star
59

persid

Persistent identifier library for GNU Emacs
Emacs Lisp
35
star
60

scientific-posters

A collection of scientific posters (with sources) made with Pages or ComicLife
Rich Text Format
34
star
61

nano-toolbar

Emacs toolbar in the header line
Emacs Lisp
33
star
62

org-imenu

org-mode side menu with filtering capability
Emacs Lisp
31
star
63

org-outer-indent

An outer indentation org mode
Emacs Lisp
30
star
64

Neurosciences

Computational Neurosciences repository
Python
30
star
65

nano-calendar

An alternative calendar for Emacs
Emacs Lisp
28
star
66

relative-date

Emacs package for formatting relative dates (dates difference)
Emacs Lisp
28
star
67

CNCC-2019

Computational Neuroscience Crash Course (CNCC 2019)
Jupyter Notebook
27
star
68

unknown-pleasures

Matplotlib animation from the Unknown Pleasures album cover (Joy Division)
Python
26
star
69

2023-dataviz-nancy

Material for dataviz course (Nancy, 2023)
Jupyter Notebook
25
star
70

conference-posters

A collection of conferences posters (with sources) made with Pages
25
star
71

aerial-emacs

A cleaner and less cluttered style for emacs
Emacs Lisp
25
star
72

2024-Dataviz

Material for the dataviz courses, Bordeaux
Jupyter Notebook
25
star
73

VSOM

Randomize Self Organizing map
Python
24
star
74

emacs-octicons

Octicons glyph name for emacs
Emacs Lisp
22
star
75

dynamic-som

Dynamic Self-Organized maps
Python
22
star
76

numpy-glm

GL Mathematics for Numpy
Python
21
star
77

Scipy-Bordeaux-2018

Notes for the Scientific Python course at the university of Bordeaux
21
star
78

Scipy-Bordeaux-2016

Course taught at the University of Bordeaux in the academic year 2015/16 for PhD students.
21
star
79

bootstrap-rst

Restructured Text Bootstrap
Python
19
star
80

nano-bell

Visual bell for GNU Emacs
Emacs Lisp
19
star
81

pendulum

Animated double pendulum using matplotlib
Python
18
star
82

spatial-computation

Spatial computation
Python
18
star
83

nano-splash

N Ī› N O Splash
Emacs Lisp
16
star
84

Scipy-Bordeaux-2017

Course taught at the University of Bordeaux in the academic year 2017 for PhD students.
16
star
85

less-is-more

A remake of the animation by Dark Horse Analytics (http://www.darkhorseanalytics.com)
Python
16
star
86

nano-minibuffer

Minibuffer for NĪ›NO Emacs
Emacs Lisp
15
star
87

org-agenda-conflict

Mark conflicting items in the org-agenda
Emacs Lisp
15
star
88

emacs-defaults

Defaults setting for vanilla emacs
Emacs Lisp
15
star
89

blog

My GitHub blog
14
star
90

ASPP-2017

Material for the Advanced Scientific Python Programming course, Nikiti, Greece, 2017
Python
14
star
91

nano-command

Emacs / Quick command in the mode-line or header-line
Emacs Lisp
13
star
92

figure-anatomy

Anatomy of a matplotlib figure
Python
13
star
93

Scipy-Bordeaux-2019

Lecture notes (UniversitƩ de Bordeaux)
Python
13
star
94

gl-bezier

Experiments on quadratic and cubic BĆ©zier curves
Python
12
star
95

mu4e-folding

Thread folding support for mu4e
Emacs Lisp
12
star
96

galaxy

Spiral galaxy simulator using the density wave theory
Python
12
star
97

EmacsConf-2022

Poster for the Emacs conference 2022
12
star
98

mu4e-thread

mu4e thread folding
Emacs Lisp
11
star
99

dana

Distributed (Asynchronous) Numerical Adaptive computing framework
Python
11
star
100

nano-read

Alternartive read functions for GNU Emacs
Emacs Lisp
11
star