I’m working on a habit/task tracking app called Habitsheets. It’s been a learning experience with the so-called PETAL stack (Phoenix, Elixir, Tailwind, Alpine, LiveView). As usual for a learning project, it’s slow going, with intermittent progress.

But as I’ve worked on Habitsheets, thinking about “features I’d like in my ideal habit/task tracking app,” some things occurred to me that don’t seem common in other apps.

This post is highlighting those features I wouldn’t mind seeing in other habit and/or task management tools.

Encouraging daily reviews

Habitsheets has a built-in concept of daily reviews. There’s a whole database table for them. The point is for the application’s UX to encourage users to regularly reflect on whether their habits are getting done.

Daily reviews appear to the user much like a regular habit. Users can open their daily review to see a concise summary of all the habits and tasks (completed or otherwise) for the day. The screen includes a five-minute timer for review timeboxing and a notes field for the user to record a short journal or whatever. When they’re done, the user clicks Done, and the daily review for that day is marked complete.

Minimizing task overload with daily agendas

(Update 2023-10-26)

I’ve since built a separate app focused on exploring the idea of minimizing task overload:

https://dust.luketurner.org

https://github.com/luketurner/dust

By default, Habitsheets doesn’t show you all your tasks; it just picks a couple (2-3) to show you each day. This reduces the overwhelming feeling that can come from a too-long task list, and eliminates the decision step of picking which tasks to do for a given day.

The idea is the user can simply do the 2-3 tasks assigned to them each day without thinking too hard.

Internally, the list of tasks for a given day is called the daily agenda and stored in the database.

Tasks can be assigned attributes like important or urgent which in turn affect which tasks are picked for the daily agenda: Urgent tasks are always picked, and important tasks are prioritized over non-important ones.

The important/urgent toggles give the user a few basic levers to control which tasks are selected, without needing them to make many decisions (compare with if the tasks were priority-ordered, which would be a more complex evaluation for the user to make and maintain over time).

Of course, sometimes the selected tasks just aren’t appropriate for a particular day. Or, sometimes you finish all your tasks and want some more. So, Habitsheets lets users manipulate their daily agendas in some controlled ways:

  • Pick a new task to add to the daily agenda. (You don’t pick the task — you just ask for a new task, and Habitsheets picks one.)
  • Discard a task and pick a new one to replace it. Tasks previously discarded won’t be picked again for that day.
  • Completely “reshuffle” the agenda, discarding all the day’s tasks, emptying the list of discarded tasks for the day, and picking all the tasks again.

This way, users can interact with their tasks on a day-to-day basis without ever looking at the full list.

However, it’s still recommended to review the full list occasionally, to remove obsolete tasks, refamiliarize yourself with someday/maybe tasks, and other long-term curation work. Habitsheets has a separate Tasks page for the full list.

Track complex habit data

By default, Habitsheets habits are simple checkboxes — either the habit was done on a given day, or it wasn’t. But there’s also the idea of additional data which can be stored alongside a habit on a given day.

Habits can have multiple pieces of additional data, each of which has a user-configured name (e.g. Number of reps) and datatype.

The datatypes are:

  • Quantity — used to store a count of something (like # of reps). A nonnegative integer value.
  • Measurement — used to store a measurement (like weight). A floating point value.
  • Duration — used to store duration (like duration of meditation). A time duration struct.
  • Sets — used to store exercise sets (like 3x12 @ 105lb). A custom struct.

So, for example, I could create a Meditation habit and give it two pieces of additional data:

  1. Meditation duration (type: duration) — how long I meditated.
  2. Meditation quality (type: quantity) — how good of a meditation was it, from 1-10.

Each day I can fill out these fields in addition to checking off the habit. Over time, I can view a longitudinal “analysis” of my additional data pieces to evaluate trends in my meditation habit.

Reminders / Push notifications

Habits need to be cued, or triggered, by something if we’re going to consistently remember to do them at the right time each day.

One effective cue is another, preexisting, habit — the approach known as habit chaining (see Atomic Habits by James Clear). This would be the approach I recommend for integrating new habits into your daily routine.

Another possible cue is a notification from some external system — a reminder. In particular, a push notification.

Reminders aren’t the ideal cue because they often show up at a time when they can’t be directly actioned on. Then they sit there, and eventually become noise. Or, they can even teach the user a learned aversion to looking at their notifications.

But, if a habit is important to complete on a daily basis (e.g. “Feed the dog”), reminders are a useful cue of last resort to make sure at least you didn’t totally forget to do the habit.

Expiration and recurring intervals

In Habitsheets, habits (or recurring tasks — the line becomes blurred) have a configurable expiration; the number of days that Habitsheets should wait before displaying the habit again after it’s been completed.

The example I always use: changing your furnace filter. You might have a habit to change the filter, with an expiration set to 30 days. This means that once you complete the habit, it won’t appear again for 30 days.

Say I change the filter on 6/1. The Change the furnace filter habit disappears until 6/31. But, I’m on vacation on 6/31, so the habit sticks around in my list. Now it’s 7/14 and I finally change the filter, and the habit disappears until 8/14.

Compare this with a monthly recurring interval, that strictly recurs on the same date every month. The expiration approach allows the interval to slide backwards if the user doesn’t complete the habit promptly.

On the other hand, expiration doesn’t work as well for something like a Pay the rent habit. That should recur once per month, and the interval shouldn’t be allowed to slide. This is more like a traditional recurring interval, like in Google Calendar/Tasks for example.

Habitsheets offers these recurring intervals well as expirations, so users can mix and match the approach for each habit.

When should users pick one or the other? Well: I think expiration makes sense for habits where there needs to be a certain cooldown time after the habit is done, before doing it again. The cooldown doesn’t kick in until the habit is actually completed. (Actually, “cooldown” was the alternative term I considered for expiration, but I thought it might be too gamer-centric.) Whereas, recurring intervals make sense for habits where they need to happen on certain dates, like every Monday.