For my daily TODO list management, I rely on TaskWarrior (see https://taskwarrior.org):

Taskwarrior manages your TODO list from your command line. It is flexible, fast, efficient, unobtrusive, does its job then gets out of your way.

You can place the taskwarrior DB (i.e. ~/.config/task/*.data) into Dropbox or any cloud utility (iCloud, owncloud, qnapsync etc.) to share the tasks across your laptops.

I combine it with a couple of additional wrappers/tools:

  • Tasksh, which offers an interactive shell that wraps Taskwarrior commands and brings the interesting review command.
  • Vit, a lightweight, fast, curses-based front end to Taskwarrior.
  • bugwarrior, a python command line utility for updating your local taskwarrior database from your forge issue trackers (Github, gitlab etc.)

Installation is pretty simple (here on Mac OS X, using Homebrew – adapt to your favorite package manager)

1
2
$> brew install task tasksh vit
$> pip3 install bugwarrior

Configuration

Taskwarrior configuration file is ~/.taskrc. Here is mine:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# Taskwarrior program configuration file.
# For more documentation, see http://taskwarrior.org or try 'man task', 'man task-faq',
# 'man task-tutorial', 'man task-color', 'man task-sync' or 'man taskrc'

# Here is an example of entries that use the default, override and blank values
#   variable=foo   -- By specifying a value, this overrides the default
#   variable=      -- By specifying no value, this means no default
#   #variable=foo  -- By commenting out the line, or deleting it, this uses the default

# Use the command 'task show' to see all defaults and overrides

# Files
data.location=~/.config/task

# Color theme
# include /usr/local/share/doc/task/rc/dark-blue-256.theme
include /usr/local/share/doc/task/rc/holidays.fr-FR.rc

default.project=sysadmins
alias.s=list project:sysadmins
journal.time=on
dateformat.annotation=Y-m-d H:N
alias.p=list project:publis
calendar.holidays=fr
uda.reviewed.type=date
uda.reviewed.label=Reviewed
report._reviewed.description=Tasksh review report.  Adjust the filter to your needs.
report._reviewed.columns=uuid
report._reviewed.sort=reviewed+,modified+
report._reviewed.filter=( reviewed.none: or reviewed.before:now-1week ) and ( +PENDING or +WAITING )

Usage

Daily usage is done via the task command. Ex:

1
2
3
4
5
6
7
$> task add Read Taskwarrior documents later
$> task add priority:H Pay bills
$> task next
$> task 2 done
$> task
$> task 1 delete
$> task add "bootstrap repo for XXX" projects:sysadmins due:eow  # Due end of week

More details: see the “Usage Examples / 30 Second Tutorial”.

Bugwarrior

bugwarrior brings the bugwarrior-pull command (typically run within a cron job) that permits to pull issues / milestones from your favorite bug-tracking system – see the list of supported services.

Configuration is not so easy, so here are some notes for configuration with a local Gitlab instance:

  1. Create a personal access Token to your account that you can use to access to the GitLab API. Menu Profiles (User Settings) / Access Tokens
    • name: bugwarrior
    • expires at: adapt to match 1 year time
    • scope: api, read_user Save the returned private token you will need later
  2. Create a personal access Token to your account that you can use to access to the GitHub API. Menu Settings / Developer settings / Personal Access Tokens: select “Generate new token”
    • Token Description: Bugwarrior
    • Scope: public_repo Save the returned private token you will need later
  3. Prepare the configuration file for bugwarrior

    $> mkdir -p .config/bugwarrior
    

Now you can adapt ~/.config/bugwarrior/bugwarriorrc to match your needs (see the Default example).

Here is mine (/!\ ADAPT <domain>, <login> and <token> accordingly): see also this gist. You will also need to adapt the { { anchor.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# bugwarriorrc -- Configuration file for Bugwarrior (see https://bugwarrior.readthedocs.io)

##############################################################################
# General stuff.
[general]

targets = gitlab.<domain>, github.com

# If unspecified, the default taskwarrior config will be used.
#taskrc = /path/to/.taskrc

# Setting this to true will shorten links with http://da.gd/
#shorten = False

# Setting this to True will include a link to the ticket in the description
inline_links = False

# Setting this to True will include a link to the ticket as an annotation
annotation_links = False

# Setting this to True will include issue comments and author name in task
# annotations
annotation_comments = False

# Defines whether or not issues should be matched based upon their description.
# In legacy mode, we will attempt to match issues to bugs based upon the
# presence of the '(bw)' marker in the task description.
# If this is false, we will only select issues having the appropriate UDA
# fields defined (which is smarter, better, newer, etc..)
legacy_matching = False

# log.level specifies the verbosity.  The default is DEBUG.
# log.level can be one of DEBUG, INFO, WARNING, ERROR, CRITICAL, DISABLED
log.level = ERROR
#DEBUG

# If log.file is specified, output will be redirected there.  If it remains
# unspecified, output is sent to sys.stderr
#log.file = /var/log/bugwarrior.log

# Configure the default description or annotation length.
#annotation_length = 45

##############################################################################
# Use hooks to run commands prior to importing from bugwarrior-pull.
# bugwarrior-pull will run the commands in the order that they are specified
# below.
#
# pre_import: The pre_import hook is invoked after all issues have been pulled
# from remote sources, but before they are synced to the TW db. If your
# pre_import script has a non-zero exit code, the `bugwarrior-pull` command will
# exit early.
[hooks]
#pre_import = /home/someuser/backup.sh, /home/someuser/sometask.sh

##############################################################################
# This section is for configuring notifications when bugwarrior-pull runs,
# and when issues are created, updated, or deleted by bugwarrior-pull.
# Three backends are currently supported:
#
#  - growlnotify (v2)   Mac OS X   "gntp" must be installed
#  - gobject            Linux      python gobject must be installed
#
# To configure, adjust the settings below.  Note that neither of the #
# "sticky" options have any effect on Linux.  They only work for
# growlnotify.
#[notifications]
#notifications = True
#backend = notify
#growlnotify
# finished_querying_sticky = False
# task_crud_sticky = True
# only_on_new_tasks = True

##############################################################################
[gitlab.<domain>]

service = gitlab
gitlab.login = <login>
gitlab.token = <token>
gitlab.host  = gitlab.<domain>
gitlab.import_labels_as_tags = True
#gitlab.label_template = gitlab_
#gitlab.include_repos =
#gitlab.exclude_regex = *
#gitlab.only_if_author = <login>
gitlab.only_if_assigned = <login>
gitlab.filter_merge_requests = False
gitlab.description_template  = { {gitlabtype|capitalize}}#{ {gitlabnumber}}: { {gitlabtitle}}  # ADAPT Liquid anchor
gitlab.project_template      = GL/{ {gitlabrepo}}     # ADAPT Liquid anchor

##############################################################################
[github.com]

service = github
github.username = <login>
github.login    = <login>
github.token    = <token>
github.description_template = GH/{ {githubtype|capitalize}}#{ {githubnumber}}: { {githubtitle}} # ADAPT Liquid anchor
github.project_template     = { {githubrepo}}       # ADAPT Liquid anchor

Note you probably wants to test the bugwarrior-pull with the log.level = DEBUG setting until you are satisfies with the behavior of the command. Then you can put it as a cron job to run every 15 minutes using crontab -e to reach the following configuration:

1
*/15 * * * *  /usr/local/bin/bugwarrior-pull

You can also prepare a wrapper script to avoid conflicting runs. Example (see also this gist):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#! /bin/bash
################################################################################
# do_bugwarrior_pull.sh - Perform the 'bugwarrior-pull' command
# See https://bugwarrior.readthedocs.io
# Time-stamp: <Wed 2017-11-22 14:58 svarrette>
#
# Copyright (c) 2017 Sebastien Varrette <Sebastien.Varrette@uni.lu>
################################################################################

LOCKFILE=$HOME/.config/task/bugwarrior.lockfile

if [ -f "${LOCKFILE}" ]; then
    # test if the file is present for at least ${ALLOWED_WAITING_TIME} hour(s)
    ALLOWED_WAITING_TIME=2
    tmptest=$(find . -mmin +$((60*${ALLOWED_WAITING_TIME})) | grep ${LOCKFILE})
    if [ $? -eq 0 ]; then
        echo "/!\ WARNING: deleting old (obsolete?) lock file '${LOCKFILE}'"
        rm -f ${LOCKFILE}
    fi
fi
if [ -n "$(which bugwarrior-pull)" ]; then
    bugwarrior-pull
fi