Using the oxford dictionary
- Productivity
- the rate at which a worker, a company or a country produces goods, and the amount produced, compared with how much time, work and money is needed to produce them
So basically we want a way to produce a large amount of work in a small amount of time (forgive me for simplifying)
- To get more things done in less time you are going to need 2 things
- a fast way to do things (emacs solves this)
- a way to schedule, plan, and keep track of those things being done
- This is where Org comes in
- Getting started is easy
- While there are at this point thousands of TODO and note programs one that has stood the test of time is ORG-MODE
- It has continually gained features seen in practically any alternative on the market
- With it’s infinite extensibility the world is yours
- While I admit nothing is forever its hard to imagine Emacs and Org-Mode becoming abandoned in my lifetime
- They are great but they can become overwhelming as tasks build up
- Org Mode provides
- Timestamps
- Deadlines
- Scheduling Time to work on something
- Plain old events
- Monitoring progress with time tracking
- Priority management
- A, B, C, etc
- Tagging
- useful for connecting tasks to projects
- Effort estimations
- good for identifying which task to handle with the available time
- Habit tracking
- For repeating tasks that may not have a set time or work period
- And More
- Timestamps
- Org Mode supports timestamps as a first class feature
- Scheduled events, deadlines, regular timestamps and more
- Multiple ways to share calendars that can fit any workflow
- While a simple calendar in some cases is enough e.g. a dentist visit
- I want to look at my up coming events and be able to reference other notes
- Often need more context
- This has always been my issue with existing TODO apps and calendar apps
- Few apps try to connect events notes and tasks together
- This is why I never stuck with Google Keep, Google calendar, or any of the markdown note tools like Obsidian
- I have a calendar event for an upcoming product demo
- I can link to a specific section of a file in a particular commit
- Change I made
- I can reference existing notes on this project
- [[file:Work.org::*\[\[https://github.com/bcgov/vc-authn-oidc/issues/429\]\[CD pipeline for dev · Issue #429 · bcgov/vc-authn-oidc\]\]][CD pipeline for dev · Issue #429 · bcgov/vc-authn-oidc]]
- I can leave notes on setup for that project and reuse them for my demo
- I can link to a specific section of a file in a particular commit
echo hello
- I can quickly reference what I did the day before using CLOSED timestamp
- We need to build the package
Setup your agenda files
I have a dedicated directory for my main org files
(setq org-directory "~/Documents/org")
I personally use every file in this directory for my agenda
(setq org-agenda-files (directory-files-recursively org-directory "\\.org$"))
AKA add all org files in this directory
Finally I bind org agenda to C-c a
(keymap-global-set "C-c a" 'org-agenda)
Lets try it out
C-c a
If there is interest I will dig into my agenda customization.
- It’s gotten a little crazy recently
<2024-04-21 Sun> Org mode’s timestamp system is one of my fav features and one of the main reasons I consider it the best tool for time managment
Use regular times for non schedule or deadlines https://orgmode.org/manual/Deadlines-and-Scheduling.html
- a lot of the time you can simply type the time in a you would say it
- This is a big pro to using org mode
e.g. C-c .
tuesday
e.g. C-c .
jan 15 2pm
<2025-01-01 Wed 14:00> <2025-02-03 Mon 01:00-13:00> <2024-04-23 Tue 01:00-13:00> <2024-04-26 Fri 01:00-13:00> <2024-04-26 Fri 13:00-14:00>
- Use scheduled for a time to work on something or time you will start
working on something
C-c C-s
- I often use this for timeblocking
- Deadline is for due dates
C-c C-d
Make common capture templates. A few must haves for me are
- Generic TODO that can capture whatever I am working on
- For me I make the default have a deadline for today
- also it will capture the region or a link to what I am looking at
("t" "Todo" entry
(file (lambda () (concat org-directory "/refile.org")))
"* TODO %?\nDEADLINE: %T\n %i\n %a")
- Timeblocking
- create a timerange to work on something
- Errands
- Assignments
- Etc
("st" "Time Block" entry
(file+headline (lambda () (concat org-directory "/Work.org"))
"Time Blocks")
"* Work On %?\nSCHEDULED: %T\n")
- Events
- Create an event for something like a trip
- capture when it is
- capture where it is
- if you import your calendar google calendar can take advantage of this
("se" "Event" entry
(file+headline (lambda () (concat org-directory "/mylife.org"))
"Events")
"* Go to the %?\n%T\n\n:PROPERTIES:\n:LOCATION: %^{location|Anywhere|Home|Work|School}\n:END:")
- Meeting
- For when I have a meeting to keep both notes about the meeting and keep track of upcoming meetings
("sm" "Meeting" entry
(file+headline (lambda () (concat org-directory "/Work.org")) "Meetings")
"* Meeting with %? :MEETING:\nSCHEDULED: %T\n:PROPERTIES:\n:LOCATION: %^{location|Anywhere|Home|Work|School|FGPC}\n:END:")
- General knowledge capture. Not scheduling related but figured I should mention it
("k" "Knowledge")
("kc" "Cool Thing" entry
(file+olp (lambda () (concat org-directory "/archive.org")) "Cool Projects")
"* %?\nEntered on %U\n %i\n %a")
("kk" "Thing I Learned" entry
(file+olp (lambda () (concat org-directory "/archive.org")) "Knowledge")
"* %? %^g\nEntered on %U\n %i\n %a")
("ki" "Ideas" entry
(file+olp (lambda () (concat org-directory "/archive.org")) "Ideas")
"* %?\nEntered on %U\n %i\n %a")
- I have a email specific ones that integrate with mu4e
- Follow up
- Schedule time to reply to an email
- Read later
- For emails I need dedicated time to go though
- Both could replaced with time blocking
- Follow up
;; Email Stuff
("e" "Email Workflow")
("ef" "Follow Up" entry
(file+olp (lambda () (concat org-directory "/Work.org")) "Follow Up")
"* TODO Follow up with %:fromname on %a\n SCHEDULED:%t\nDEADLINE: %(org-insert-time-stamp (org-read-date nil t \"+2d\"))\n\n%i")
("er" "Read Later" entry
(file+olp (lambda () (concat org-directory "/Work.org")) "Read Later")
"* TODO Read %:subject\n SCHEDULED:%t\nDEADLINE: %(org-insert-time-stamp (org-read-date nil t \"+2d\"))\n\n%a\n%i")
(setq org-capture-templates
'(("t" "Todo" entry (file (lambda () (concat org-directory "/refile.org")))
"* TODO %?\nDEADLINE: %T\n %i\n %a")
("m" "movie")
("mt" "movie" entry
(file+headline (lambda () (concat org-directory "/mylife.org")) "Movies to Watch"))
("v" "Video Idea" entry
(file+olp (lambda () (concat org-directory "/youtube.org"))
"YouTube" "Video Ideas")
"*RESEARCHING%?\n%? %a\n")
("g" "Gift")
("gs" "Gift For Seren" checkitem
(file+headline (lambda () (concat org-directory "/archive.org")) "Gifts for Seren")
nil
:jump-to-captured t)
("gw" "Wish List" checkitem
(file+headline (lambda () (concat org-directory "/site/wishlist.org")) "Wish list")
nil
:jump-to-captured t)
("u" "Update Current Clocked Heading" text
(clock)
"hello world %?"
:unnarrowed t)
("k" "Knowledge")
("kc" "Cool Thing" entry
(file+olp (lambda () (concat org-directory "/archive.org")) "Cool Projects")
"* %?\nEntered on %U\n %i\n %a")
("kk" "Thing I Learned" entry
(file+olp (lambda () (concat org-directory "/archive.org")) "Knowledge")
"* %? %^g\nEntered on %U\n %i\n %a")
("ki" "Ideas" entry
(file+olp (lambda () (concat org-directory "/archive.org")) "Ideas")
"* %?\nEntered on %U\n %i\n %a")
("kT" "Thoughts" entry
(file+olp (lambda () (concat org-directory "/archive.org")) "Thoughts")
"* %?\nEntered on %U\n %i\n %a")
("kw" "Word I learnt" entry
(file+olp (lambda () (concat org-directory "/archive.org")) "Words")
"* %?\nEntered on %U\n %i\n %a")
("s" "Schedule")
;; Not sure I even want to have this
;; ("sE" "Errand" entry (file (lambda () (concat org-directory "/refile.org")))
;; "* TODO %? :errand\nDEADLINE: %T\n %a")
("sm" "Meeting" entry
(file+headline (lambda () (concat org-directory "/Work.org")) "Meetings")
"* Meeting with %? :MEETING:\nSCHEDULED: %T\n:PROPERTIES:\n:LOCATION: %^{location|Anywhere|Home|Work|School|FGPC}\n:END:")
("se" "Event" entry
(file+headline (lambda () (concat org-directory "/mylife.org"))
"Events")
"* Go to the %?\n%T\n\n:PROPERTIES:\n:LOCATION: %^{location|Anywhere|Home|Work|School}\n:END:")
("st" "Time Block" entry
(file+headline (lambda () (concat org-directory "/Work.org"))
"Time Blocks")
"* Work On %?\nSCHEDULED: %T\n")
;; Org Protocol
;; ("pc" "Cool Thing" entry
;; (file+olp (lambda () (concat org-directory "/archive.org")) "Cool Projects")
;; "* %^{Title}\n\n %^g\nEntered on %U\n Source: %u, %c\n\n %i")
("p" "Thing I Learned" entry
(file+olp (lambda () (concat org-directory "/archive.org")) "Knowledge")
"* %^{Title}")
;; Email Stuff
("e" "Email Workflow")
("ef" "Follow Up" entry
(file+olp (lambda () (concat org-directory "/Work.org")) "Follow Up")
"* TODO Follow up with %:fromname on %a\n SCHEDULED:%t\nDEADLINE: %(org-insert-time-stamp (org-read-date nil t \"+2d\"))\n\n%i")
("er" "Read Later" entry
(file+olp (lambda () (concat org-directory "/Work.org")) "Read Later")
"* TODO Read %:subject\n SCHEDULED:%t\nDEADLINE: %(org-insert-time-stamp (org-read-date nil t \"+2d\"))\n\n%a\n%i")))
(setopt org-capture-templates-contexts
;; I repeat "m" since org mode only supports this format
'(("e" "e" ((in-mode . "mu4e-view-mode")
(in-mode . "mu4e-compose-mode")))))
- Calendar support with org export to iCal
(setopt org-icalendar-use-scheduled '(todo-start event-if-not-todo))
(org-icalendar-combine-agenda-files)
(copy-file org-icalendar-combined-agenda-file "/ssh:user@server:/home/gavinfre/public_html/cal.ics" t)
- ICSx5 on mobile to sync this calendar with mobile
- Importing iCal
- There are lots of options but I use ical2org.awk
- There is also a python and a Go version
If one does not support exporting the way you like give one of the others a go
You can get the public URL for your google calendar like so
#!/bin/sh
# Depends on https://github.com/msherry/ical2org
ERRORFILE=$(mktemp XXX.txt)
trap 'rm $ERRORFILE' EXIT TERM HUP
# Google Calendar
curl -s $(pass gcalics) 2>>$ERRORFILE |
awk -f ~/.scripts/ical2org.awk > /home/gavinok/Documents/org/gcal.org 2>>$ERRORFILE
# Holidays
curl -s \
https://calendar.google.com/calendar/embed?src=en.canadian%23holiday%40group.v.calendar.google.com&ctz=America%2FDawson_Creek 2>>$ERRORFILE |
awk -f ~/.scripts/ical2org.awk > /home/gavinok/Documents/org/holidays.org 2>>$ERRORFILE
ERRORS=$(cat $ERRORFILE)
if [ -z $ERRORS ]
then notify-send "Google Calendar Has Been Added To Notes"
else notify-send "$ERRORS"
fi
If you want a proper 2 way sync I recommend using caldav
This basically replaces the previous 2 approaches
You will need a server to be setup.
(use-package org-caldav
:ensure t
:custom
(org-caldav-url "https://nextcloud.org/remote.php/dav/calendars/gavinfreeborn")
(org-caldav-calendar-id "personal")
(org-caldav-inbox "~/Documents/org/nextcloud-inbox.org")
(org-caldav-files org-agenda-files)
(org-icalendar-timezone "America/Vancouver")
:commands (org-caldav-sync))
How I manage Notifications
There are multiple approaches
- syohex/org-notify: System notifications of org agenda deadlines
- Amy Grinn / org-yaap · GitLab
- I have had success with this in the past
As usual for an Emacs user I rolled my own (sorta)
Emacs comes with a built in package for notifying you of upcoming appointments
appt
I hacked on appt to use desktop notifications
In addition I also added support for sending notifications to my phone using
(use-package appt
:demand t
:defer 5
:custom
((appt-announce-method 'appt-persistant-message-announce)
(appt-message-warning-time 15)
(appt-display-duration 360)
(appt-disp-window-function #'my/appt-display)
(appt-delete-window-function #'ignore))
:init
(defun my/appt-display (min-to-app _new-time appt-msg)
(require 'notifications)
;; Close the last iteration of this notification
(when-let ((repid (get-last-note appt-msg)))
(notifications-close-notification repid))
(let ((title (pcase min-to-app
("0" "Appointment Is Starting")
("1" "Appointment in 1 Minute")
(min (concat " Appointment in " min " Minutes"))))
(body appt-msg)
(urgency (if (< (string-to-number min-to-app) 3)
'critical
'normal)))
;; Send a desktop notification for this appointment
(store-last-note
(funcall (if (eq system-type 'android)
;; support for android notifications
'android-notifications-notify
'notifications-notify)
:title title
:body body
:urgency urgency
:actions '("Open" "Open this appointment")
:on-action (lambda (_id _key) (org-agenda 'd)))
appt-msg)
;; Notify me on my phone
(plz 'post "https://ntfy.sh/my-emacs-notifications"
:headers `(("Title" . ,title)
("Priority" . ,(if (eql urgency 'critical)
"high"
"default"))
("Tags" . "calendar")
("Markdown" . "yes"))
:body body)))
;; Check for if a notification needs to be sent
(appt-activate +1)
;; generate appointments from my org agenda
(org-agenda-to-appt)
;; Run when I am idle for a minute at a time
;; (usually when looking at my browser)
(defvar appt-update-org-timer
;; wait till emacs is idle for 1 minute before processing org appointments
(run-with-idle-timer 60 t #'org-agenda-to-appt)
"Timer used to update appt to the current org events"))
Why did I make this?
It’s flexible and easy to understand.
I don’t need to manage a seperate list of files for my notifications
and agenda since org-agenda-to-appt
I no longer use this but for those of you worried about conflicting times there is a great package called org-conflict that you can use to check that a time does not conflict with an existing events
While not schedule specific but important when you can’t remember the time of an event I use consult-recoll to search for any notes. I use consult’s category cycling to only look through the org results.
alternatively org-agenda supports a full text search however it is synchronous which causes the UI to lockup and it’s pretty slow.
I hope I have made it clear the multitude of different ways you can use org mode to boost your productivity when it comes to task and time management