ankursinha.in/blog

neuroscience/fedora/musings

Mon 25 December 2017

Managing tasks, time, and making sure one takes a break: Integrating Taskwarrior, Timewarrior, and Gnome Pomodoro

Posted by ankur in Tech (1141 words, approximately a 5 minute read)

With the new year, come resolutions. On many a list will there be a determination to do better in the coming year, to be more organised, more efficient, more productive.

I'm quite organised myself. I have lists, calendars, reminders, budgets, and all of that. Being a FOSS person, my first thought, inevitably, is to see if there's a piece of software that would aid me.

This post documents how one can get Taskwarrior, Timewarrior, and Gnome Pomodoro to work together to manage tasks, track them, and break those long hours into smaller bits with regular breaks.

Taskwarrior helps manage tasks

For managing tasks, there's the rather excellent Taskwarrior. It's command line, and there are various user interfaces that have been developed for it too. (Vit is one that provides a terminal interface with Vim like keybindings, and there's a Vim plugin too.) One can even set up a Taskwarrior server to sync the data between different machines. There are a few hosted services that give free Taskwarrior server accounts too. Perhaps the best bit, is excellent documentation. Taskwarrior really does make it easy to get things done.

Timewarrior tracks time spent on tasks

Taskwarrior is not meant to be a time tracker, and upstream says so quite plainly. In fact, upstream went ahead and wrote Timewarrior for that purpose entirely. Like Taskwarrior, Timewarrior is also a command line tool.

Integrating the two is quite easy, using a Taskwarrior hook, as documented here. Each time a task is started, or stopped in Taskwarrior, the hook calls Timewarrior to start or stop tracking the task too.

Note: to ensure that this hook is run before the Gnome Pomodoro hook that we set up in the next section, please save the hook file as ~/.task/hooks/on-modify.00-timewarrior

Gnome Pomodoro reminds us to take regular breaks

So, one can manage tasks, and track the time spent working on them, and that's great. It was sufficient for me for quite a while, before I realised that I was spending too much time at my desk. What made it worse was the realisation that for us white collar professionals, a majority of our lives will be spent at a desk typing away on a computer. There's enough research to show that spending all those long hours working in a seated position is bad for one's health.

So, I went looking for the changes I should make to my work regime, and ran into the Pomodoro technique. The idea is to take short breaks at regular intervals. One can use these to get up and walk around a bit, get them 10,000 steps! There are plenty of tools that implement the Pomodoro technique. A simple timer works too. The one I settled on is Gnome Pomodoro which integrates really well with Gnome Shell. Every 25 minutes, it'll remind the user to take a 5 minute break.

Now, let us integrate Gnome Pomodoro with both Taskwarrior and Timewarrior:

  • When a task is started using task <filter> start, Taskwarrior already begins to track it using the hook, and a Pomodoro should also be started.
  • When a Pomodoro is over and Gnome Pomodoro notifies of a break, Timewarrior should be paused too.
  • When the break is over, and another Pomodoro starts, Timewarrior should resume tracking the task.
  • When a task is stopped, Taskwarrior will stop tracking it via the hook already, and the Pomodoro should be stopped as well.

This is a very simple set up. A task must be started using Taskwarrior here, and each time Gnome Pomodoro pauses and resumes from breaks, the same task will be resumed unless it was stopped and another started.

It turned out to be quite easy because of how well these three tools have been designed. Here's a Taskwarrior hook for Gnome Pomodoro similar to the one for Timewarrior:

#!/usr/bin/env python2
# API is here: https://taskwarrior.org/docs/hooks.html
# To be saved at ~/.task/hooks/on-modify.01-gnome-pomodoro to ensure it is
# run after the timewarrior hook, which should be saved as
# ~/.task/hooks/on-modify.00-timewarrior
# Otherwise, this is run before which then runs the Gnome-Pomodoro actions
# things get quite messy!
import json
import os
import sys

# Make no changes to the task, simply observe.
old = json.loads(sys.stdin.readline())
new = json.loads(sys.stdin.readline())
print(json.dumps(new))

# Start pomodoro when task is started
if 'start' in new and 'start' not in old:
    os.system('gnome-pomodoro --start')
# Stop pomodoro when a task is stopped
elif 'start' not in new and 'start' in old:
    os.system('gnome-pomodoro --stop')

It's called when a task is modified. It checks the old and new states. If a task is started, it starts gnome-pomodoro, and when it's stopped, it stops it. This is one direction.

The other direction requires some tinkering with Gnome Pomodoro to set up custom scripts. In the preferences, one must enable the "Custom actions" plugin:

A screenshot showing the plugin preferences in Gnome Pomodoro.

Then, a "Custom Actions" entry will be added to the preferences. We need to add two of them. The first, resumes Timewarrior tracking when the Pomodoro resumes:

A screenshot showing custom action that will resume timew after a break.

Similarly, the second stops Timewarrior when a break begins, or the user pauses the Pomodoro:

A screenshot showing custom action that will stop timew at the start of a break.

(If no tasks are active, Timewarrior doesn't do anything, so that case does not need to be handled separately.)

There are certain limitations to what commands can go in there, so I've used a shell script to implement the required logic:

#!/bin/bash
# save as ~/bin/track-timew.sh
# note that ~/bin/ must be in PATH

resume ()
{
    timew || timew continue
}

pause ()
{
    timew && timew stop
}

clean ()
{
    # sed only does greedy regex so it's slightly complicated
    # could use perl to make this a lot simpler because perl does non
    # greedy too.
    for entry in $(timew summary :ids | grep -o '@.*' | sed -E 's/(^@[[:digit:]]+[[:space:]]+)/\1 |/' | sed -E 's/([[:digit:]]+:[[:digit:]]+:[[:digit:]]+ )/| \1/' | sed 's/|.*|//' | sed -E 's/[[:space:]]{2,}/ /' | cut -d ' ' -f 1,4 | grep -E '0:0[01]:..' | cut -d ' ' -f 1 | tr '\n' ' '); do timew delete "$entry"; done
}

usage ()
{
    echo "$0: wrapper script around timewarrior to carry out common tasks"
    echo "For use with Gnome-Pomodoro's action plugin"
    echo
    echo "Usage: $0 <option>"
    echo
    echo "OPTIONS:"
    echo "-r    resume tracking of most recently tracked task"
    echo "-p    pause tracking"
    echo "-c    clean up short tasks (less than 2 minutes long)"
}

# check for options
if [ "$#" -eq 0 ]; then
    usage
    exit 1
fi

# parse options
while getopts "rpch" OPTION
do
    case $OPTION in
        r)
            resume
            exit 0
            ;;
        p)
            pause
            exit 0
            ;;
        c)
            clean
            exit 0
            ;;
        h)
            usage
            exit 1
            ;;
        ?)
            usage
            exit 1
            ;;
    esac
done

The script is quite simple, and I hope, self-explanatory too. I'll leave interpretation of the clean function to the reader ;)

That's all there is to it. There must be other ways of doing the same thing, possibly with different tools too, but this system required least changes to my current workflow. Do remember that these tools can only aid us. It is us that need to show that bit of discipline to follow the plan through. I hope some will find it helpful, and may the new year be healthier and more productive for us all! :)


 
    
 
 

Comments