A command-line task manager

Best Laid Plans

© Photo by Kelly Sikkema on Unsplash

© Photo by Kelly Sikkema on Unsplash

Author(s):

The dstask personal tracker lets you manage your to-do list from the command line. Dstask uses Git version control to store tasks, letting you synchronize your to-do list across multiple devices.

After finding a much-needed network cable under a pile of junk in the basement, I decided it was time to add cleaning up the basement to my to-do list. To manage personal tasks (even unpleasant ones like this), the dstask personal tracker can help you prioritize tasks and track completion.

Unlike many other task managers, dstask exclusively runs on the command line. With a short and succinct command, you can add a new task or mark off a completed one. On request, dstask provides a list of all pending tasks, sorted by urgency. Filters help you stay on track in the task jungle. As an added benefit, you can use your task list to show customers or your boss your completed work.

Under the hood, dstask stores the pending tasks in the Git version management system, letting you sync tasks across all your devices. However, unlike dstask's other features, synchronization requires some Git know-how.

Kickstart

To get dstask up and running, first install Git using your package manager. To install Git on Ubuntu, type:

sudo apt install git

Next, go to the dstask project page on GitHub [1] and click on the current version number on the right below Releases. Under Assets, download the version for Linux, dstask-darwin-amd64.

Rename the resulting program dstask and make it executable. To do this, run:

chrmod +x dstask

You do not have to actually install dstask, but the developer does recommend storing dstask in /usr/local/bin, which lets all of the system's users call the program directly by typing dstask.

After that, you still have to create the Git repository where dstask stores all the tasks and become acquainted with Git (Listing 1). Replace editorial@linux-user.en and Tim Sch¸rmann with your own email address and full name. Without this information, you will always get error messages when working with dstask.

Listing 1

Creating a Git Repository

$ mkdir ~/.dstask && git -C ~/.dstask init
$ git config --global user.email "editorial@linux-user.en"
$ git config --global user.name "Tim Sch¸rmann"

Come On In

To add the basement cleanup task to dstask, use the call shown in line 1 of Listing 2. The add command tells the program to create a new task, which is described in the following brief summary (clean up basement).

Listing 2

Adding Tasks

01 $ dstask add clean up basement +basement +private P2
02 $ dstask add +private basement +clean up basement P2

Dstask adds all words that follow a plus sign (+) to the task as keywords (i.e., basement and private in Listing 2). These tags will help you later on when searching for a specific task. You can also add the tags to the summary, as shown in line 2 of Listing 2.

In addition, you can set the task priority, which is shown by the number following P. Dstask supports priority levels P3 to P0, with P0 for urgent tasks and P2 for normal priority tasks. In Listing 2, I've set my basement cleanup task to P2, since it's not time critical. Dstask automatically defaults to P2 if you don't include the priority level.

Roll Up Your Sleeves

To see what dstask has on your to-do list, just call dstask. The program assigns a consecutive ID to each task. Entering dstask 1 shows detailed information about the task (Figure 1). Dstask ignores case sensitivity in the tags.

Figure 1: Dstask removes the tags from the task name. To see an individual task's detailed information (including tags), enter dstask followed by the task number (1). (You can ignore the messages in light gray from Git.)

The detailed information also shows the task status. Immediately after creation, the task will be shown as pending. When you head down to the basement and pick up the first box, call

dstask start clean up basement

to change the status. This switches the task to the active state, signifying that the task is in progress. If you take a break, stop processing with

dstask stop clean up basement

which toggles the task back to the pending state.

Once the basement is finally clean, mark the task as done by entering

dstask done clean up basement

Even though dstask is done reminding you about this task, it will still store the task, thereby creating a record of your completed tasks for your boss or client.

To get a report on all completed tasks, enter

dstask show-resolved

Dstask automatically sorts the tasks by weeks. If you want to remove a task from the dstask repository, use the following command:

dstask remove clean up basement

Sticky Notes

During my basement cleanup, I discovered some old novels that Aunt Dorothy lent me. I need to make a note of this somehow as a reminder. Dstask lets you attach as many notes to a task as you like. To create a reminder for Aunt Dorothy's books, use the command from line 1 of Listing 3. The number stands for the task ID. In the example, dstask then pins a note reading return novels to Aunt Dorothy onto the clean up basement task.

Listing 3

Pinning Notes

01 $ dstask note 1 return novels to Aunt Dorothy
02 $ dstask add clean up basement +basement P2 / return novels to Aunt Dorothy

Using the same principle, you can create as many additional notes as you like. Markdown experts can also use tags, but dstask 0.23.2 is not currently capable of evaluating or visually rendering Markdown tags. You can also tell dstask to directly add a note when you add a task (Figure 2). To do this, simply append a slash followed by the note (Listing 3, line 2).

Figure 2: Dstask lists notes at the end. Notes are also useful for checklists, where each note reflects an individual sub-task.

Project Work

While you're cleaning up the basement, you might as well tackle the garage and declutter the shoe closet. All three cleaning tasks could be grouped together to create a spring cleaning project.

Dstask lets you add individual tasks to a project by adding another parameter when you create a task. The tasks in lines 1 and 2 of Listing 4 are part of the spring cleaning project specified after the project: parameter. (Note again that dstask is not case sensitive.)

Listing 4

Organizing Tasks in Projects

01 $ dstask add clean up garage +private P3 project:spring cleaning
02 $ dstask add declutter shoe closet +Private P1 project:Spring Cleaning
03 $ dstask modify 1 -Private +Books P1 project:Spring cleaning

As shown in Figure 3, a call to dstask reveals that the original task clean up basement does not yet belong to any project. To change this, you can quickly modify the information by typing

dstask modify 1 project:Spring cleaning
Figure 3: When you call dstask, you see a list of pending tasks. Dstask displays any existing notes in light gray in the Summary column.

The number again stands for the corresponding task ID (where 1 is the basement cleanup task). You can use modify to adjust the priority, keywords, and the project itself; a minus sign removes the tag in question (Listing 4, line 3).

Targeted Intervention

Use the dstask edit 1 command to make a correction in a note. Dstask then opens all the details of the specified task in a text editor (Figure 4).

Figure 4: The editor shows you how dstask stores the task under the hood: a text file in YAML format.

The editor that opens is defined by the $EDITOR environment variable. This is often nano, but it could also be Vim or another editor. Some distributions, such as Ubuntu 20.04 and later, do not set a text editor. Instead, you have to set the environment variable explicitly with the commands shown in Listing 5. When editing a task, make sure that you only adjust the values to the right of the colons. As shown in Figure 3, modify the project name to the right of the project: parameter. When you are done, save your adjustments and exit the editor (in nano, press Ctrl+O followed by Ctrl+X).

Listing 5

Setting the Environment Variable

$ echo "export EDITOR=nano" > ~/.bash_profile
$ source ~/.bash_profile

While I was removing the sneakers from the shoe closet, I also dumped the waste paper in the recycling bin. To retroactively log this completed task, dstask has a log action. It works exactly like add, but immediately sets the project to resolved (Listing 6).

Listing 6

Logging Tasks

$ dstask log waste paper dumped +Private P3 project:spring cleaning

In the meantime, quite a few spring cleaning tasks have accumulated. The most urgent are revealed by typing dstask or dstask next. The task manager sorts the list by the priority and the age of the task, placing your next task at the top of the list. To see all the tasks that you have started but not yet finished, enter:

dstask show-active

To see all paused tasks, enter:

dstask show-paused

Dstask supports some further display formats (see Table 1). If dstask does not find any matching tasks or data for an action, it just stubbornly provides a command overview.

Table 1

Display Formats and Commands

Action

Function

next

List of major tasks

show-projects

List of all projects including the resolved tasks

show-tags

List of all assigned tags

show-active

List of all started tasks

show-paused

List of all tasks that were started and then paused

show-open

List of all tasks not yet finished

show-resolved

List of all completed tasks

show-templates

List of all templates

show-unorganised

List of all tasks that do not have a tag or are not assigned to a project

In Context

Tasks have a tendency to accumulate over time resulting in unwieldy to-do lists. To filter out unwanted tasks, you can use the context command to specify the filtering criteria (Listing 7).

Listing 7

Context

$ dstask context +private -basement project:spring cleaning

The command in Listing 7 tells dstask to only pay attention to tasks tagged as private that do not contain the basement keyword, but that do belong to the spring cleaning project. For now, the tool ignores all other tasks. If you create a new task at this point, it will automatically be tagged private and will belong to the spring cleaning project.

To reset the filter, type:

dstask context none

This tells dstask to get back to work on all existing tasks again. A call to dstask reveals the active context. If you are missing a task, check the context first (Figure 5).

Figure 5: The clean up basement task does not match the rules of the defined context, so it no longer appears in the list of pending tasks.

Templates

You probably need to clean up your desk far more often than your basement. For recurring tasks, templates can save you some typing (Figure 6). Templates are initially conventional tasks, but you create them using the template keyword (Listing 8, line 1). To show all existing templates, enter

dstask show-templates

which ignores any remaining actions.

Listing 8

Templates

01 $ dstask template clean up desk +Private P3 project:administration
02 $ dstask add template:4 sort pencils
Figure 6: First a new template is created and then a new task is created based on the template. Since dstask treats the templates like tasks internally, the template is assigned an ID of 4.

To create a new task based on a template, you run add again, but reference the template. The command from line 2 of Listing 8 tells dstask to create a new task that takes all the settings from the template ID 4, but uses the Sort pencils string as the summary.

Git Games

The dstask git log command (Figure 7) returns the latest completed actions. Actions can be undone by typing dstask undo 3, where the number (3) indicates the number of actions to be revoked, starting with the last action performed.

Figure 7: The git action lets you directly invoke other Git commands including log.

If you want to synchronize your task collection with other devices, dstask needs to be installed on those devices as well. In addition, you need a Git repository that all devices can access, such as one on GitHub. Make sure that only you have access to the repository; do not make it public to the entire Internet.

First, create the ~/.dstask/ directory on all devices and clone the contents of the external Git repository to it using git clone. You can now create and manage your tasks in the usual way. To tell dstask to push all the changes to the external Git repository, call dstask sync.

On another PC, call dstask sync again. This tells dstask to sync with the Git repository and fetch the current state. Under the hood, dstask calls the git pull and git push commands. If you are familiar with Git, you can run other Git commands via the dstask git action.

More Efficient Typing

If you want to manage many tasks regularly in Bash with dstask, the work can be accelerated significantly by using an alias or script. You can create an alias, for example, using alias t=dstask. With this alias, you now just need to type t instead of dstask, which could save some typing.

You can also use a script. You'll find a .dstask-bash-completions.sh file on dstask's GitHub page. If you run this by typing

source .dstask-bash-completions.sh

you will find that Bash now knows all the dstask parameters and automatically completes them when you press the Tab key.

However, this only works if you have moved dstask to /usr/local/bin/ or another appropriate location in $PATH. To avoid having to repeatedly type the command discussed here, you might want to add it to your ~/.bashrc file.

If you want to set up autocompletion in Zsh, use the .dstask-zsh-completions.sh script from the GitHub page.

Conclusions

Dstask quickly manages all your pending tasks at the command line. If you frequently manage your system at the keyboard in a terminal window, you can particularly benefit from this approach to task management. The range of functions is fine for everyday use, but it does not come close to replacing a full-fledged task manager.

Having said this, the developer does plan to add support for sub-tasks and advanced project management in future releases. For example, you will be able to assign deadlines for tasks. The documentation is currently limited to the online help retrieved by dstask help. If you append an action such as add to this command, you will see a detailed description for the respective command only.