My Organizational Workflow

How I use org-mode and other tools to streamline my life

This is an up-to-date document on my org-mode workflow. This is inspired by “A Guide to My Organizational Workflow: How to Streamline Your Life” and other articles like Getting Boxes Done, Getting Boxes Done, the Code, Refiling Trees to Files. In a gist this is about how I take notes and how I keep track on what I work on and what I need to work on.

This is part of My Emacs System.

Introduction

I am not sure exactly when, but overtime, my life grew in complexity, and I decide along the way to use org-mode to help me with that. Even though org-mode could be considered as an implementation detail of my workflow, it’s really hard to separate from it. I’ll try my best to describe the workflow without mentionning org-mode and from there, we’ll see how my setup does it.

Many of the ideas presented here derive from the Getting Things Done methodology, but adapted and expanded to meet my personal needs. With that workflow, I am trying to spint my time more wisely and focus on what’s important to me. This is not a silver bullet though, and is an always in progress work.

Goals

I really liked the goal list from “A Guide to My Organizational Workflow: How to Streamline Your Life”, so I kinda took heavy inspiration from it.

In order to determine how effective an organizational system is, it is important to have clearly enumerated aims: what is the system being designed to enable? Your goals may be different, but my system is structured to prioritize the following:

  • Ensure that I never miss a task, meeting, or deadline (note: the meeting part is tricky);
  • Manage tasks that I need to work on;
  • Manage tasks that I share with and have assigned to others (when I depend on it);
  • Keep a permanent record of my work and research, and in a way that can be easily shared with others if necessary;
  • Collect my thoughts, writings, and half-baked ideas;
  • Ensure that my local progress—on a daily or monthly basis—is in service of my long-term goals (this is kinda hard to do);
  • Finally: ensure I enjoy my life and make time for fun and friends! My system is meant to organize, not confine.

One key idea to keep in mind as well is that an organizational system should be flexible. Life is complicated and unexpected items—both good and bad—can appear at a moment’s notice. While it may not be immediately clear where a new task or project belongs, one should always have the ability to add new files or lists to which the new items can be added. Additionally, I do occasionally discover a file or project will outgrow the way I decided to structure it at its inception. My tools support fast and easy refactoring when necessary so that I can restructure a project to reflect my updated understanding of the problems it was intended to solve. The greater the effort required to reorganize when necessary, the less frequently it will happen and the effectiveness of the organizational system will decline. The tools I will describe later on work well for me, but you should find those tools that work best for you.

The above is the reason why I am using org-mode : it’s plain text, it’s flexible — you can add data (properties, tags, …), you can define your behavior (using emacs-lisp code).

My workflow

As described earlier, my workflow is loosely based on some concept from the Getting Things Done methodology, but adapted and expanded to meet my personal needs. One of the core principles of the Getting Things Done methodology, is that “the mind is for thinking, not remembering”. Everything that may need to be accomplished—or that you might someday want to accomplish—should be written down.

I also really like the boxes comparison from Getting Boxes Done.

On my workbench is a box. Actually, a few boxes. Each uncompleted project goes into a box… no lost screws. Sure unpacking and packing between each session is a hassle, but since the best projects take a few weekends, boxes are required.

Non-workbench-oriented projects go into mental boxes, and I’m thinking of my self organization in terms of boxes. Thoughts don’t go into physical boxes, but in my world, they live in text files. […]

My usual workflow for solving a problem involves breaking up a high-level objective into increasingly smaller goals until I can make progress towards accomplishing it. org-mode allows me to collect my tasks and projects when needed and build the lists. As I work, I log my progress, my thoughts, where I get stuck, temporary images or figures, intermediate results, how to reproduce my work, and so on. Note taking is a critical part of my thinking process, so notes and their parent tasks should coexist.

If we talk in files now, this looks like the following:

archive
this is where I archive my project and notes if they don’t make sense anymore.
notes
this is my notes boxes, where I keep my journal entry (monthly files), private and public notes (the one published here).
projects
this is my project boxes, where I keep a set of files containing tasks I need to do for specific projects (related to my work, or personal). Each file represent a project and should be archived at some point, except a bunch of special ones (inbox, incubate, next, …)
  • inbox is where I capture ideas, task and links that I need to review later.
  • incubate is where ideas (captured previously in inbox) are going while waiting for being picked up.
  • next is where I put small task that can be quickly done, like a doing a quick backup, etc. My wish is to have the least amount of tasks in next.

Implementation

Constants and registers

Let’s dig into the files and folders I’ll use across the rest of my configuration.

(defconst org-directory "~/desktop/org/"
  "org-mode directory, where most of the org-mode file lives")
(defconst org-projects-dir (expand-file-name "projects" org-directory)
  "Primary tasks directory.")
(defconst org-notes-dir (expand-file-name "notes" org-directory)
  "Directory of shareable, technical notes.")
(defconst org-archive-dir (expand-file-name "archive" org-directory)
  "Directory of shareable, technical notes.")
(defconst org-completed-dir (expand-file-name "projects" org-archive-dir)
  "Directory of completed project files.")
(defconst org-inbox-file (expand-file-name "inbox.org" org-projects-dir)
  "New stuff collected in this file.")
(defconst org-next-file (expand-file-name "next.org" org-projects-dir)
  "Todo *next* collected in this file.")
(defconst org-incubate-file (expand-file-name "incubate.org" org-projects-dir)
  "Ideas simmering on back burner.")
(defconst org-babel-library-file (expand-file-name "org_library_of_babel.org" org-notes-dir)
  "Org babel library.")

I’m also using registers to quickly access some files, mainly the inbox file, the incubate file and the next file.

(set-register ?i `(file . ,org-inbox-file))
(set-register ?I `(file . ,org-incubate-file))
(set-register ?n `(file . ,org-next-file))

TODO Main configuration

(use-package org
  :ensure org-plus-contrib ;; load from the package instead of internal
  :mode (("\\.org$" . org-mode)
         ("\\.org.draft$" . org-mode))
  :commands (org-agenda org-capture)
  :bind (("C-c o l" . org-store-link)
         ("C-c o r r" . org-refile)
         ("C-c o a a" . org-agenda)
         ("C-c o a r" . my/reload-org-agenda-files)
         ("C-c o s" . org-sort)
         ("<f12>" . org-agenda)
         ("C-c o c" . org-capture)
         ;; Skeletons
         ("C-c o i p" . vde/org-project)
         ("C-c o i n" . vde/org-www-post))
  :config
  (define-skeleton vde/org-project
    "new org-mode project"
    nil
    > "#+TITLE: " (skeleton-read "Title: ") \n
    > "#+FILETAGS: " (skeleton-read "Tags: ") \n
    > _ \n
    > "#+BEGIN: clocktable :scope file :maxlevel 2 :emphasize nil :link t" \n
    > "#+END:" \n
    > _ \n)
  (define-skeleton vde/org-www-post
    "new www post"
    nil
    > "#+title: " (skeleton-read "Title: ") \n
    > "#+date: " (format-time-string "<%Y-%M-%d %a>") \n
    > "#+filetags: " (skeleton-read "Tags: ") \n
    > "#+setupfile: ../templates/post.org" \n
    > _ \n
    > "* Introduction"
    )
  ;; Org Babel configurations
  (when (file-exists-p org-babel-library-file)
    (org-babel-lob-ingest org-babel-library-file))
  (defun my/org-agenda-files ()
    `(,org-projects-dir
      "~/src/home/tasks.org"
      "~/src/www/tasks.org"))
  (defun my/reload-org-agenda-files ()
    (interactive)
    (setq org-agenda-files (my/org-agenda-files)))
  (setq org-agenda-files (my/org-agenda-files)
        org-agenda-file-regexp "^[a-zA-Z0-9-_]+.org$"
        org-use-speed-commands t
        org-special-ctrl-a/e t
        org-special-ctrl-k t
        org-todo-keywords '((sequence "TODO(t)" "NEXT(n)" "STARTED(s)" "|" "DONE(d!)" "CANCELED(c@/!)")
                            (sequence "WAITING(w@/!)" "SOMEDAY(s)" "|" "CANCELED(c@/!)")
                            (sequence "IDEA(i)" "|" "CANCELED(c@/!)"))
        org-todo-state-tags-triggers '(("CANCELLED" ("CANCELLED" . t))
                                       ("WAITING" ("WAITING" . t))
                                       (done ("WAITING"))
                                       ("TODO" ("WAITING") ("CANCELLED"))
                                       ("NEXT" ("WAITING") ("CANCELLED"))
                                       ("DONE" ("WAITING") ("CANCELLED")))
        org-use-tag-inheritance t
        org-tag-alist '(("linux") ("nixos") ("emacs") ("org")
                        ("openshift") ("redhat") ("tektoncd") ("kubernetes") ("knative" ) ("docker")
                        ("docs") ("code") ("review")
                        (:startgroup . nil)
                        ("#home" . ?h) ("#work" . ?w) ("#errand" . ?e) ("#health" . ?l)
                        (:endgroup . nil)
                        (:startgroup . nil)
                        ("#link" . ?i) ("#read" . ?r) ("#project" . ?p)
                        (:endgroup . nil))
        org-log-done 'time
        org-log-redeadline 'time
        org-log-reschedule 'time
        org-log-into-drawer t
        org-enforce-todo-dependencies t
        org-refile-targets (append '((org-inbox-file :level . 0))
                                   (->>
                                    (directory-files org-projects-dir nil ".org")
                                    (--remove (s-starts-with? "." it))
                                    (--map (format "%s/%s" org-projects-dir it))
                                    (--map `(,it :level . 1))))
        org-refile-use-outline-path 'file
        org-refile-allow-creating-parent-nodes 'confirm
        org-outline-path-complete-in-steps nil
        org-columns-default-format "%80ITEM(Task) %TODO %3PRIORITY %10Effort(Effort){:} %10CLOCKSUM"
        org-fontify-whole-heading-line t
        org-pretty-entities t
        org-ellipsis " ⤵"
        org-archive-location (concat org-completed-dir "/%s::datetree/")
        org-use-property-inheritance t
        org-priority 67
        org-priority-faces '((?A . "#ff2600")
                             (?B . "#ff5900")
                             (?C . "#ff9200")
                             (?D . "#747474"))
        org-global-properties (quote (("EFFORT_ALL" . "0:15 0:30 0:45 1:00 2:00 3:00 4:00 5:00 6:00 0:00")
                                      ("STYLE_ALL" . "habit")))
        org-blank-before-new-entry '((heading . t)
                                     (plain-list-item . nil))
        org-insert-heading-respect-content t
        org-yank-adjusted-subtrees t
        org-image-actual-width nil
        org-startup-with-inline-images nil
        org-list-demote-modify-bullet '(("+" . "-") ("-" . "+"))
        org-catch-invisible-edits 'error
        ;; Put theses into a minor mode
        org-indent-indentation-per-level 1
        org-cycle-separator-lines 1
        org-adapt-indentation nil
        org-hide-leading-stars t
        org-hide-emphasis-markers t)
  (setcar (nthcdr 4 org-emphasis-regexp-components) 10)
  :hook (org-mode . vde/org-mode-hook))

(defun vde/org-mode-hook ()
  "Org-mode hook"
  (setq show-trailing-whitespace t)
  (when (not (eq major-mode 'org-agenda-mode))
    (setq fill-column 90)
    (auto-revert-mode)
    (auto-fill-mode)
    (org-indent-mode)
    (set (make-local-variable 'company-backends)
         '(company-emoji company-capf company-files company-dabbrev))
    (company-mode 1)
    (add-hook 'before-save-hook #'save-and-update-includes nil 'make-it-local)))

TODO Agenda

(use-package org-agenda
  :after org
  :commands (org-agenda)
  :bind (("C-c o a a" . org-agenda)
         ("<f12>" . org-agenda)
         ("C-c o r a" . org-agenda-refile))
  :config
  (use-package org-super-agenda
    :config (org-super-agenda-mode))
  (setq org-agenda-span 'day
        org-agenda-start-on-weekday 1
        org-agenda-include-diary t
        org-agenda-window-setup 'current-window
        org-agenda-skip-scheduled-if-done nil
        org-agenda-compact-blocks t
        org-agenda-sticky t
        org-super-agenda-header-separator ""
        org-agenda-custom-commands
        `(("w" "Agenda"
           ((agenda "")
            (tags-todo "-goals-incubate-inbox+TODO=\"STARTED\""
                       ((org-agenda-overriding-header "Ongoing")))
            (tags-todo "-goals-incubate-inbox+TODO=\"NEXT\""
                       ((org-agenda-overriding-header "Next"))))
           ((org-super-agenda-groups
             '((:name "Important" :priority "A")
               (:name "Scheduled" :time-grid t)
               (:habit t))))
           (org-agenda-list)))))
(use-package org-gcal
  :after (org)
  :commands (org-gcal-fetch)
  :config
  (require 'netrc)
  (setq-default org-gcal-remove-cancelled-events t)
  (defun get-authinfo (host port)
    (let* ((netrc (netrc-parse (expand-file-name "~/.authinfo.gpg")))
           (hostentry (netrc-machine netrc host port port)))
      (when hostentry (netrc-get hostentry "password"))))

  (setq org-gcal-client-id "959564825992-kvc7ofe9640cpc8ibgjqqgpi15e89nkn.apps.googleusercontent.com"
        org-gcal-client-secret (get-authinfo "gcal.api" "9999")
        org-gcal-file-alist '(("vdemeest@redhat.com" . "~/desktop/org/projects/schedule.org"))))

TODO Habits

(use-package org-habit
  :after (org)
  :config
  (setq org-habit-show-habits-only-for-today nil
        org-habit-graph-column 80))

TODO Capture

(use-package org-capture
  :after org
  :commands (org-capture)
  :config

  (add-to-list 'org-capture-templates
               `("l" "Link" entry
                 (file ,org-inbox-file)
                 "* %a\n%U\n%?\n%i"
                 :empty-lines 1))

  (add-to-list 'org-capture-templates
               `("t" "Tasks"))
  (add-to-list 'org-capture-templates
               `("tt" "New task" entry
                 (file ,org-inbox-file)
                 "* %?\n:PROPERTIES:\n:CREATED:%U\n:END:\n\n%i\n\nFrom: %a"
                 :empty-lines 1))
  (add-to-list 'org-capture-templates
               `("tr" "PR Review" entry
                 (file ,org-inbox-file)
                 "* TODO review gh:%^{issue} :review:\n:PROPERTIES:\n:CREATED:%U\n:END:\n\n%i\n%?\nFrom: %a"
                 :empty-lines 1))

  ;; (add-to-list 'org-capture-templates
  ;;              `("m" "Meeting notes" entry
  ;;                (file+datetree ,org-meeting-notes-file)
  ;;                (file ,(concat user-emacs-directory "/etc/orgmode/meeting-notes.org"))))

  (add-to-list 'org-capture-templates
               `("w" "Writing"))
  :bind (("C-c o c" . org-capture)))


(use-package org-capture-pop-frame
  :after org)

TODO Templates

* %^{meeting}

- Actions ::
  #+BEGIN: columnview :id local :match "/TODO|DONE" :format "%ITEM(What) %TAGS(Who) %DEADLINE(When) %TODO(State)"
  | What                                | Who        | When | State |
  |-------------------------------------+------------+------+-------|
  #+END:
- Decisions ::
  #+BEGIN: columnview :id local :match "Decision" :format "%ITEM(Decisions)"
  | Decisions |
  |-----------|
  #+END:

** Present at meeting
  - [ ]
** Agenda
- %?
** Notes
- Use =:Decision:= tag for decision
- Use entry with =TODO= (or =DONE=) for actions
** %(format-time-string org-journal-time-format) weekly review :weekly:review:
%U

- [ ] review ~inbox.org~
  Clean the file by either
  - refiling it to ~incubate.org~
  - removing it / archiving it
- [ ] review ~incubate.org~
  - Is something worth becoming a project
  - Is something not worth thinking about anymore ?
- [ ] empty mail inbox (and create task if needed)
  - [ ] work
  - [ ] perso
- [ ] Review next week ~F12 n w f~
- [ ] review ~org-mode~ workflow
  - *what works, what doesn't ?*
  - *is there task / stuck projects ?*
  - *enhancement possible ?*
- [ ] export previous agenda (somewhere)

TODO Protocol

(use-package org-protocol
  :after org)

TODO Clocking

(use-package org-clock
  :after org
  :commands (org-clock-in org-clock-out org-clock-goto)
  :config
  ;; Setup hooks for clock persistance
  (org-clock-persistence-insinuate)
  (setq org-clock-clocked-in-display nil
        ;; Show lot of clocking history so it's easy to pick items off the C-F11 list
        org-clock-history-length 23
        ;; Change tasks to STARTED when clocking in
        org-clock-in-switch-to-state 'vde/clock-in-to-started
        ;; Clock out when moving task to a done state
        org-clock-out-when-done t
        ;; Save the running clock and all clock history when exiting Emacs, load it on startup
        org-clock-persist t)
  (use-package find-lisp)
  (defun vde/is-project-p ()
    "Any task with a todo keyword subtask"
    (save-restriction
      (widen)
      (let ((has-subtask)
            (subtree-end (save-excursion (org-end-of-subtree t)))
            (is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1)))
        (save-excursion
          (forward-line 1)
          (while (and (not has-subtask)
                      (< (point) subtree-end)
                      (re-search-forward "^\*+ " subtree-end t))
            (when (member (org-get-todo-state) org-todo-keywords-1)
              (setq has-subtask t))))
        (and is-a-task has-subtask))))

  (defun vde/is-project-subtree-p ()
    "Any task with a todo keyword that is in a project subtree.
Callers of this function already widen the buffer view."
    (let ((task (save-excursion (org-back-to-heading 'invisible-ok)
                                (point))))
      (save-excursion
        (vde/find-project-task)
        (if (equal (point) task)
            nil
          t))))

  (defun vde/find-project-task ()
    "Move point to the parent (project) task if any"
    (save-restriction
      (widen)
      (let ((parent-task (save-excursion (org-back-to-heading 'invisible-ok) (point))))
        (while (org-up-heading-safe)
          (when (member (nth 2 (org-heading-components)) org-todo-keywords-1)
            (setq parent-task (point))))
        (goto-char parent-task)
        parent-task)))

  (defun vde/is-task-p ()
    "Any task with a todo keyword and no subtask"
    (save-restriction
      (widen)
      (let ((has-subtask)
            (subtree-end (save-excursion (org-end-of-subtree t)))
            (is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1)))
        (save-excursion
          (forward-line 1)
          (while (and (not has-subtask)
                      (< (point) subtree-end)
                      (re-search-forward "^\*+ " subtree-end t))
            (when (member (org-get-todo-state) org-todo-keywords-1)
              (setq has-subtask t))))
        (and is-a-task (not has-subtask)))))

  (defun vde/is-subproject-p ()
    "Any task which is a subtask of another project"
    (let ((is-subproject)
          (is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1)))
      (save-excursion
        (while (and (not is-subproject) (org-up-heading-safe))
          (when (member (nth 2 (org-heading-components)) org-todo-keywords-1)
            (setq is-subproject t))))
      (and is-a-task is-subproject)))

  (defun vde/clock-in-to-started (kw)
    "Switch a task from TODO to STARTED when clocking in.
Skips capture tasks, projects, and subprojects.
Switch projects and subprojects from STARTED back to TODO"
    (when (not (and (boundp 'org-capture-mode) org-capture-mode))
      (cond
       ((and (member (org-get-todo-state) (list "TODO"))
             (vde/is-task-p))
        "STARTED")
       ((and (member (org-get-todo-state) (list "STARTED"))
             (vde/is-project-p))
        "TODO"))))
  :bind (("<f11>" . org-clock-goto)))

TODO Notes taking

(use-package org-roam
  :commands (org-roam org-roam-build-cache)
  ;; :hook
  ;; (after-init . org-roam-mode)
  :bind (("C-c o n" . org-roam-mode)
         :map org-roam-mode-map
         (("C-c n l" . org-roam)
          ("C-c n f" . org-roam-find-file)
          ("C-c n g" . org-roam-show-graph)
          ("C-c n b" . org-roam-switch-to-buffer))
         :map org-mode-map
         (("C-c n i" . org-roam-insert)))
  :custom
  (org-roam-directory org-notes-dir)
  :custom-face
  (org-roam-link ((t (:inherit org-link :foreground "#C991E1"))))
  :config
  (require 'org-roam-protocol)
  ;; (defun jethro/conditional-hugo-enable ()
  ;;     (save-excursion
  ;;       (if (cdr (assoc "SETUPFILE" (org-roam--extract-global-props '("SETUPFILE"))))
  ;;           (org-hugo-auto-export-mode +1)
  ;;         (org-hugo-auto-export-mode -1))))
  ;;
  ;;   (with-eval-after-load 'org
  ;;     (defun my/org-roam--backlinks-list (file)
  ;;       (if (org-roam--org-roam-file-p file)
  ;;           (--reduce-from
  ;;            (concat acc (format "- [[file:%s][%s]]\n"
  ;;                                (file-relative-name (car it) org-roam-directory)
  ;;                                (org-roam--get-title-or-slug (car it))))
  ;;            "" (org-roam-sql [:select [file-from]
  ;;                                      :from file-links
  ;;                                      :where (= file-to $s1)
  ;;                                      :and file-from :not :like $s2] file "%private%"))
  ;;         ""))
  ;;     (defun my/org-export-preprocessor (_backend)
  ;;       (let ((links (my/org-roam--backlinks-list (buffer-file-name))))
  ;;         (unless (string= links "")
  ;;           (save-excursion
  ;;             (goto-char (point-max))
  ;;             (insert (concat "\n* Backlinks\n" links))))))
  ;;     (add-hook 'org-export-before-processing-hook 'my/org-export-preprocessor))
  (setq org-roam-capture-ref-templates
        '(("r" "ref" plain #'org-roam-capture--get-point ""
           :file-name "${slug}"
           :head "#+title: ${title}\n#+roam_key: ${ref}\n\n${body}"
           :unnarrowed t)))
  (setq org-roam-capture-templates
        '(("d" "default" plain (function org-roam--capture-get-point)
           "%?"
           :file-name "${slug}"
#+TITLE: ${title}\n"
           :unnarrowed t)
          ("p" "private" plain (function org-roam--capture-get-point)
           "%?"
           :file-name "${slug}.private"
           :head "#+TITLE: ${title}\n"
           :unnarrowed t))))

TODO Rebuild configurations files

Most of my configuration files are store in my home monorepo. That said, most of those are actually automatically generated from litterate org-mode files coming from my notes.

I want to be able to update those all in one go. Even better, I would like to make sure I update those before killing emacs.

(use-package org
  :defer 2
  :config
  (defun vde/tangle-all-notes ()
    "Produce files from my notes folder.
This function will attempt to tangle all org files from `org-notes-dir'. The
assumption is that those will generate configuration file (in `~/src/home'),
and thus keeping the configuration source up-to-date"
    (mapc (lambda (x) (org-babel-tangle-file x))
          (ignore-errors
            (directory-files-recursively org-notes-dir "\.org$")))))

TODO Journaling

(use-package org-journal
  :commands (org-journal-new-entry org-capture)
  :after (org-capture)
  :bind
  (("C-c n j" . org-journal-new-entry)
   ("C-c o j" . org-journal-new-entry))
  :init
  (defun org-journal-find-location ()
    "Open today's journal, but inhibiting inserting the heading, leaving that to the template."
    (org-journal-new-entry t)
    ;; position pont on the journal's top-level heading so that org-capture will add the new entry as a child.
    (goto-char (point-max)))
  (add-to-list 'org-capture-templates
               `("j" "Journal"))
  (add-to-list 'org-capture-templates
               `("jj" "Journal entry" entry (function org-journal-find-location)
                 "** %(format-time-string org-journal-time-format)%^{Title}\n%i%?"
                 :empty-lines 1 :clock-in t :clock-resume t))
  (add-to-list 'org-capture-templates
               `("je" "Weekly review" entry (function org-journal-find-location)
                 (file ,(expand-file-name "etc/orgmode/weekly.org" user-emacs-directory))
                 :empty-lines 1 :clock-in t :clock-resume t))
  :custom
  (org-journal-date-prefix "* ")
  (org-journal-file-header "#+TITLE: %Y-v%m Journal\n\n")
  (org-journal-file-format "%Y-%m.private.org")
  (org-journal-file-type 'monthly)
  (org-journal-dir org-notes-dir)
  (org-journal-date-format "%A, %d %B %Y")
  (org-journal-enable-agenda-integration nil))

TODO Litterate programming

Although not really in my “organization” workflow, this is related to org-mode so this leaves here for now.

(use-package org-src
  :after (org)
  :config
  (setq org-src-fontify-natively t
        org-src-tab-acts-natively t
        org-src-window-setup 'current-window
        org-edit-src-content-indentation 0))

TODO Babel

(use-package ob-async
  :after org
  :commands (ob-async-org-babel-execute-src-block))
(use-package ob-css
  :after org
  :commands (org-babel-execute:css))
(use-package ob-dot
  :after org
  :commands (org-babel-execute:dot))
(use-package ob-ditaa
  :after org
  :commands (org-babel-execute:ditaa)
  :config
  (setq org-ditaa-jar-path "/home/vincent/.nix-profile/lib/ditaa.jar"))
(use-package ob-emacs-lisp
  :after org
  :commands (org-babel-execute:emacs-lisp org-babel-execute:elisp))
(use-package ob-go
  :after org
  :commands (org-babel-execute:go))
(use-package ob-gnuplot
  :after org
  :commands (org-babel-execute:gnuplot))
(use-package ob-http
  :after org
  :commands (org-babel-execute:http))
(use-package ob-js
  :after org
  :commands (org-babel-execute:js))
(use-package ob-latex
  :after org
  :commands (org-babel-execute:latex))
(use-package ob-python
  :after org
  :commands (org-babel-execute:python))
(use-package ob-shell
  :after org
  :commands (org-babel-execute:ash
             org-babel-execute:bash
             org-babel-execute:csh
             org-babel-execute:dash
             org-babel-execute:fish
             org-babel-execute:ksh
             org-babel-execute:mksh
             org-babel-execute:posh
             org-babel-execute:sh
             org-babel-execute:shell
             org-babel-execute:zsh))
(use-package ob-doc-makefile
  :after org
  :commands (org-babel-execute:makefile))

TODO Diary

(use-package diary-lib
  :after (org)
  :config
  (setq diary-entry-marker "diary")
  (setq diary-show-holidays-flag t)
  (setq diary-header-line-flag nil)
  (setq diary-mail-days 3)
  (setq diary-number-of-entries 3)
  (setq diary-comment-start ";")
  (setq diary-comment-end "")
  (setq diary-date-forms
        '((day "/" month "[^/0-9]")
          (day "/" month "/" year "[^0-9]")
          (day " *" monthname " *" year "[^0-9]")
          (monthname " *" day "[^,0-9]")
          (monthname " *" day ", *" year "[^0-9]")
          (year "[-/]" month "[-/]" day "[^0-9]")
          (dayname "\\W"))))

TODO Miscellaneous

(use-package org-id
  :after org
  :commands contrib/org-id-headlines
  :config
  (setq org-id-link-to-org-use-id
        'create-if-interactive-and-no-custom-id)

  (defun contrib/org-get-id (&optional pom create prefix)
    "Get the CUSTOM_ID property of the entry at point-or-marker
POM. If POM is nil, refer to the entry at point. If the entry
does not have an CUSTOM_ID, the function returns nil. However,
when CREATE is non nil, create a CUSTOM_ID if none is present
already. PREFIX will be passed through to `org-id-new'. In any
case, the CUSTOM_ID of the entry is returned."
    (org-with-point-at pom
      (let ((id (org-entry-get nil "CUSTOM_ID")))
        (cond
         ((and id (stringp id) (string-match "\\S-" id))
          id)
         (create
          (setq id (org-id-new (concat prefix "h")))
          (org-entry-put pom "CUSTOM_ID" id)
          (org-id-add-location id (buffer-file-name (buffer-base-buffer)))
          id)))))

  (defun contrib/org-id-headlines ()
    "Add CUSTOM_ID properties to all headlines in the current
file which do not already have one."
    (interactive)
    (org-map-entries
     (funcall 'contrib/org-get-id (point) 'create))))
(use-package org-crypt
  :after (org)
  :config
  (org-crypt-use-before-save-magic)
  (setq org-tags-exclude-from-inheritance '("crypt")))
(use-package org-tempo
  :after (org))
(use-package org-attach
  :after org
  :config
  (setq org-link-abbrev-alist '(("att" . org-attach-expand-link))))
(use-package ox-publish
  :after org
  :commands (org-publish org-publish-all org-publish-project org-publish-current-project org-publish-current-file)
  :config
  (setq org-html-coding-system 'utf-8-unix))

Triage

# -*- mode: org; eval: (add-hook 'after-save-hook (lambda () (org-babel-tangle)) nil t) -*-
  • Remove slack from phone (or personal tablets) With working remote, it’s even more important to draw the line
  • Have timeboxed « slacking off » session by slacking off, I mean twitter, reddit, …
  • Take a medium to long walk during the day Better in the middle, by medium to long I mean at least an hour walk
  • It’s ok to set smaller pomodoro from time to time, 25 is the “longest” limit, not the lowest one
  • Apply it as much as you can (i.e. not interruption)
  • Pomodoro technique
  • https://thelifelifebalance.com/pros-and-cons-of-pomodoro/
  • Phone / tablet
    • Remove most apps
    • Remove most notifications
    • Grayscale most of the time

TODO org-mode Workflow

Logbook
nil

This goes into emacs.org.

Ideas:

  • filter org file(s) with a tags & co
    • use case: journal.org with weekly-review only, worklog only, …
    • subject (go, emacs, …) to build article or gather thoughts, idea, reviews, …
  • Heavy usage of org-protocol to list reviews done, and more quickly capture content from the browser

The rest is deprecated 😅

Deprecated

Let’s try to think about “TODOs” management in the light of todoist and org-mode. Reasons to use todoist are :

  • write task/todo items on-the-go on any devices — this is way harder with org-mode.
  • list and mark task/todo as done from anywhere
  • share some list with others (mainly @houbeb)
  • have some nice stats

Reasons to use org-mode are :

  • integrated with my editor, agenda, notes, mail, …
  • easily customizable (dashboard, agenda, search, filters, org-links, …)
  • all text, data are own by me, replicated
  • clock possibility (related to work, so adding some context to it)

One idea is to be able to synchronize org-mode and todoist

  • only part of the org-mode todo list (i.e. a todoist.org file)
  • mainly (and at first) used todoist -> org-mode
  • syncing two ways the means adding a new element that doesn’t have the required properties in the todoist.org file

TODO Do some writeup about org-mode usage and workflow

TODO Add a reviewing org-protocol capture template

Properties

:CREATED:[2020-04-16 Thu 10:57]

That way I track more easily the long review by just using a bookmark.

TODO Better worklog entries

  • Substree in a datetime tree (see if it is possible)
  • In a separate journal ?

TODO Fix meetings notes

Properties

:CREATED:[2020-04-02 Thu 17:41]

  1. Capture template doesn’t work
  2. Can we make Actions and Decision per “tree” ? (if not, meeting notes might be one file for each meeting)
  3. Ideas
    • New tree
    • Better template
    • Stay in the capture while it’s happening

From: Decisions

TODO quick writing org-mode template

Logbook
nil
Properties

:CREATED:[2019-12-20 Fri 10:09]

^^ some of those could be normal template instead of org-mode capture templates

TODO org-protocol support for more templates

TODO org-mode entry ordering

  • By TODO keyword, then priority
  • Bind it to sthg (else than ^)

Legacy

(use-package org
  :defer t
  :config

  (defvar org-capture-templates (list))
  (setq org-protocol-default-template-key "l")

  ;; images
  (setq org-image-actual-width nil
        org-startup-with-inline-images nil)

  ;; Tasks (-> inbox)

  ;; Journal

  (add-to-list 'ispell-skip-region-alist '(":\\(PROPERTIES\\|LOGBOOK\\):" ":END:"))
  (add-to-list 'ispell-skip-region-alist '("#\\+BEGIN_SRC" "#\\+END_SRC"))
  (add-to-list 'ispell-skip-region-alist '("#\\+BEGIN_EXAMPLE" "#\\+END_EXAMPLE"))

  ;; org-links
  ;; from http://endlessparentheses.com/use-org-mode-links-for-absolutely-anything.html
  (org-link-set-parameters "tag"
                           :follow #'endless/follow-tag-link)
  (defun endless/follow-tag-link (tag)
    "Display a list of TODO headlines with tag TAG.
With prefix argument, also display headlines without a TODO keyword."
    (org-tags-view (null current-prefix-arg) tag))

  (org-link-set-parameters
   "org"
   :complete (lambda () (+org-link-read-file "org" org-directory))
   :follow   (lambda (link) (find-file (expand-file-name link org-directory)))
   :face     (lambda (link)
               (if (file-exists-p (expand-file-name link org-directory))
                   'org-link
                 'error)))
  (defun +org-link-read-file (key dir)
    (let ((file (read-file-name (format "%s: " (capitalize key)) dir)))
      (format "%s:%s"
              key
              (file-relative-name file dir))))
  )

Foobar

(message "foo")
(message "bar")
;; Yo

<<foo>>
<<bar>>

Configuration layout

Here we define the config-org file that gets generated by the source blocks in our Org document. This is the file that actually gets loaded on startup. The placeholders in angled brackets correspond to the NAME directives above the SRC blocks throughout this document.

;;; config-org.el --- -*- lexical-binding: t; -*-
;;; Commentary:
;;; Configuration of orgmode.
;;; Code:

(use-package s)

<<constants-and-registers>>
<<main>>
<<agenda>>
<<capture>>
<<protocol>>
<<clock>>
<<habits>>
<<src>>
<<links>>
<<babel>>
<<notes>>
<<journaling>>
<<misc>>
<<diary>>

<<legacy>>

(provide 'config-org)
;;; config-org.el ends here