I think I have a reasonable handle on agenda custom sorting, but I can't figure out how habits sort themselves within that agendas.

For a certain agenda view I sort as '(time-up habit-down todo-state-down priority-down) which largely does exactly what I want and expect. The daily schedule is at the top and the due habits without scheduled/deadline hours are at the bottom. Within habits anything overdue (red in default graph) is first, then anything due today (yellow in default graph), then anything available but not due today (green in default graph). Great!

But today for example I see two tasks due today, one at C priority and one at A priority. Why is the C priority listed first?

In the non-habit tasks 'priority-down puts A above B above C but in habits it looks reversed.

EDIT: Looking further into this only has me more confused. I can't see. any explanation for this ordering:I can't see any explanation for habit ordering here. What I notice here that differs from the normal sorting rule mentioned above is:

  • In items due today an unprioritized item (#E in my config) is above an A priority item
  • The 'available' habits are not sorted by priority at all - CBCCB
  • They aren't alphabetical either: basement is before upstairs, but vacuum is before practice.
  • They aren't sorted by category; House is split two at the top and one at the bottom.

1 Answer 1


The key function is org-habit-get-priority which provides a numerical priority value for a habit. This value is then used as part of the sorting habit-down and will take higher precedence than your later keys. The default definition of org-habit-get-priority takes into account the consistency graph in a number of ways: it starts at 1000, adjusts by 10 for each day before/after scheduled date, adds 50 if deadline is today, adds 100 for each day after deadline, subtracts 10 each day until deadline. What you see in your ordering is

  1. an overdue item (red)
  2. two items that will be overdue tomorrow (yellow)
  3. one item that will be overdue in two days (green)
  4. three items that will be overdue in in 6 days (green)
  5. one item that has even longer til it is overdue (green)

Within categories 2. and 4. your priority-down decides the ordering, so Cs come after Bs.

The actual function definition is

(defsubst org-habit-get-priority (habit &optional moment)
  "Determine the relative priority of a habit.
This must take into account not just urgency, but consistency as well."
  (let ((pri 1000)
    (now (if moment (time-to-days moment) (org-today)))
    (scheduled (org-habit-scheduled habit))
    (deadline (org-habit-deadline habit)))
    ;; add 10 for every day past the scheduled date, and subtract for every
    ;; day before it
    (setq pri (+ pri (* (- now scheduled) 10)))
    ;; add 50 if the deadline is today
    (if (and (/= scheduled deadline)
         (= now deadline))
    (setq pri (+ pri 50)))
    ;; add 100 for every day beyond the deadline date, and subtract 10 for
    ;; every day before it
    (let ((slip (- now (1- deadline))))
      (if (> slip 0)
      (setq pri (+ pri (* slip 100)))
    (setq pri (+ pri (* slip 10)))))

Should you wish to ignore exactly how many days before the deadline the non-overdue tasks are, one would want to remove the final computation (setq pri (+ pri (* slip 10))). Unfortunately the function is defined via defsubst which means that is inlined, and so a change to this means that there would be no effect without recompiling org mode (it is also loaded by the agenda code).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.