Scatterbrained: Revisiting the “doing” CLI

Back in 2011 I started tracking the minutiae of my work days using VoodooPad. It was partly for record keeping, but mostly to be able to walk away from my computer and still be able to remember what I was doing when I got back. I can be very, very scatterbrained. After VoodooPad, I had a system going using QuickQuestion and nvALT. Then it was Day One. By 2014 I’d come up with a solution in the form of a command line utility called doing. The journey was well documented up to that point in a series called, appropriately enough, “Scatterbrained.”

I haven’t written much about doing since then, but I continue to use it daily. It’s come a long way. It not only creates rich logs of my time at my computer, it also handles time tracking and reporting and integrates with my system via LaunchBar, various automations, and GeekTool. You know how git log can be really useful after a long night of hacking, or a few days of being away?1 This is that, but for everything else, and it’s brimming with handy features.

Given I’ve been working on this as needed for 5 years now, it hasn’t felt like a descent into madness as much as a gentle slide into areas of questionable judgment. I find it a very useful tool, though, as long as I don’t think too much about how much time I’ve put into it.

After publishing a few new versions over the last couple of months, I thought it might be time to remind potential users (people who read this blog and enjoy my brand of madness) that it exists. This is going to be a longish post where I get to talk giddily about all the cool stuff this little tool can do. If you’re already sold — or at least enough to skip the spiel — and want to skip right to the documentation and the latest version, just head straight to the doing project page.

Before we go much further, I should make something clear. doing is primarily designed for use from the command line in your terminal of choice. It’s by a nerd, for nerds. I have, however, integrated it with LaunchBar and other systems over the years. It’s flexible. The LaunchBar action is included below, if you’re interested.

The basic idea of doing is to provide a way to keep track of the little things I work on over the course of a day, both as a reminder after I leave and forget what I was working on, and as a way to track my productivity.

It does this using a terminal command with an intuitive syntax. The command updates a simple TaskPaper-formatted text file. (You may be aware of my love of plain text…) It does some automatic time tracking, has a variety of tools for viewing your entries, and includes a few ways to do things like filtering, flagging, or archiving them. More tools than I’ll be able to fit into a blog post, even a long one, but the documentation is detailed and up-to-date.

If you’ve used Git before, the concept will be familiar. Just type in what you were working on, like you would for a commit, including as many notes as needed, and hit Enter to add it to the log. Doing even has query features that I dare say make it even more useful than git log. Sometimes. It depends on the situation. How about this: “in a very particular set of circumstances for a very specific set of needs, doing is more useful than git log.”

The Basics

You can install doing using Rubygems, i.e. gem install doing (you might need sudo gem install doing depending on your configuration). Once that’s successful, you can start recording entries right away, but I’d wait until you’ve read through the configuration section of the docs before going overboard. There are a few things you’ll want to adjust, including the location and name of your “doing file.”

Like git, doing uses subcommands, meaning you call doing and the next word in the command will determine what action it performs. This allows for (almost) natural syntaxes for most actions. The main command for adding a new entry is now, i.e. doing now [what you are doing]. now is also aliased as next as of recent versions, just because that sometimes makes more semantic sense. Like I said, almost human syntax.

You only need quotes around the entry if it contains characters the shell needs escaped, so I can just type doing now writing about doing. An entry will be created with the current time as the start time. There are features for modifying the start and finish times using natural language, but we’ll get to those in a bit.

You can add @tags in the text of an entry to allow for future sorting and filtering fun. (Tags use @ instead of #, first because that’s a TaskPaper standard, and second because # causes a lot of extra work on the command line.) You can also include notes with a -n "[Note Text]" flag.

If you want to modify tags and notes after the fact, just run doing tag writing to add @writing to the last entry, or doing note to open an editor, the results of which are appended as a note. And when you’re done doing what you’re doing, you can just run doing finish to add a stop time to the last task. Remember, all of this is stored in a TaskPaper file that you can manually edit at any time. Just run doing open to open the file in your default text editor.

You can see all of doing’s commands by running doing help. That will show you something like:

NAME
    doing - A CLI for a What Was I Doing system

SYNOPSIS
    doing [global options] command [command options] [arguments...]

VERSION
    1.0.25

GLOBAL OPTIONS
    -f, --doing_file=arg - Specify a different doing_file (default: none)
    --help               - Show this message
    --[no-]notes         - Output notes if included in the template (default: enabled)
    --stdout             - Send results report to STDOUT instead of STDERR
    --version            - Display the program version

COMMANDS
    add_section  - Add a new section to the "doing" file
    archive      - Move entries in between sections
    choose       - Select a section to display from a menu
    colors       - List available color variables for configuration templates and views
    config       - Edit the configuration file
    done         - Add a completed item with @done(date). No argument finishes last entry.
    finish       - Mark last X entries as @done
    grep, search - Search for entries
    help         - Shows a list of commands or help for one command
    last         - Show the last entry
    later        - Add an item to the Later section
    mark         - Mark last entry as highlighted
    meanwhile    - Finish any running @meanwhile tasks and optionally create a new one
    note         - Add a note to the last entry
    now, next    - Add an entry
    on           - List entries for a date
    open         - Open the "doing" file in an editor
    recent       - List recent entries
    sections     - List sections
    show         - List all entries
    tag          - Tag last entry
    templates    - Output HTML templates for customization
    today        - List entries from today
    undo         - Undo the last change to the doing_file
    view         - Display a user-created view
    views        - List available custom views
    yesterday    - List entries from yesterday

You can get help for any subcommand by running doing help [command], e.g. doing help meanwhile.

Seeing What You’re Doing

There are myriad ways to filter and view your tasks. Commands like doing recent, last, today, and yesterday are pretty self-explanatory, but the real workhorses are the doing show and doing view commands. Combined with custom templates, you can do everything from terminal time tracking to viewing HTML-formatted work logs in the browser. You can even get CSV and JSON output for passing to other tools.

doing show accepts a section name and/or tag names. By default doing creates sections (what would be projects in TaskPaper) for “Currently” and “Archive”. If you use doing later, it automatically adds a “Later” section. You can add as many custom sections as you want, either by editing the file directly (doing open) or by using doing add_section [Section Name].

For example, I keep a running list of random ideas in a separate section (called “Ideas,” obviously). It lets me get ideas out of my head without going down rabbit holes or worrying that I’ll forget about them. I can add to that section using doing done -s Ideas My great @idea. Note that I used done because I’m not time tracking these, so it makes sense to add them as finished entries right away, and I also included an @idea tag. I actually have an alias for this that lets me just type idea My great idea, and the word “idea” is always automatically tagged using a tagging whitelist in my configuration file. (See the section on autotagging further down.)

Now I can just run doing show Ideas and see all of my ideas listed out. I can also run doing show @idea to show entries tagged with @idea across all of my sections. And I can combine the two to show just entries with a particular tag within a particular section, e.g. doing show Ideas @coding. You can even include multiple tags and use the -b [AND|OR|NONE] flag to define the boolean used to search. So doing show -b OR @idea @brainstorm @thinking would show any entry tagged with any of @idea, @brainstorm, or @thinking.

Output of
Output of doing show

The view command is similar to show, but allows you to customize all of the aspects of the view, from what section/tags to include to the output template. Using the .doingrc config file (documentation), you can define named views with custom parameters and templates. I have a view set up called “ideas” that lets me run doing view ideas and have my ideas shown like this:

Output of

This is accomplished with a section in the YAML-formatted config file:

views:
  ideas:
    template: "\U0001F4A1 %softpurple%title %boldblack%note%default"
    order: asc
    count: 20
    section: Ideas
    wrap_width: 0

Among my other views is one for GeekTool2 which puts my three most recent entries across all sections on my Desktop, formatted as single lines with no notes, and a date format string that keeps everything aligned nicely (when used with a mono font).

Doing on the Desktop with GeekTool
Doing on the Desktop with GeekTool

The view for that one:

views:
	geektool:
	    date_format: "%a %_I:%M%P"
	    tags_bool: NONE
	    tags_color: green
	    template: "%magenta%date %boldcyan> %white%title%default"
	    order: asc
	    count: 3
	    section: All
	    tags: cancelled
	    wrap_width: 0

There are a ton of options for the view and show commands, so run doing help show and doing help view to get a feel for them. There’s even an HTML output option (doing show [section/tag] -o html) you can pipe to bcat or hcat. It works with any view or show command, just add -o html anywhere after the subcommand, e.g. doing show Archive @marked -o html|bcat. You can also output any show or view command as JSON or CSV, overriding the template to provide structured data.

doing output in the browser
doing output in the browser

Tracking Time

At the outset I had no intention of using doing for time tracking. Time tracking kind of evolved over time. It’s still not going to beat an actual time tracking app, nor any automated time tracking like Timing. Nonetheless, doing has some handy tools.

All of these commands operate on the “Currently” section by default, and can be pointed at other sections using -s SECTION_NAME. The section name is fuzzy matched and case insensitive.

As I mentioned previously, commands like now and done allow various combinations of --took and --back for fudging times if you haven’t been religiously logging every step. Using --back lets you modify the start date with natural language, e.g. doing now --back 30m Starting the thing to start it 30 minutes ago. Similarly, doing done --took 1h will finish the last task by adding an hour to whatever the start date was. You can also add a task complete with retrospective time tracking using a single command, e.g. doing done --took 2h working on website typography.

There’s also a meanwhile command that lets you maintain an overarching task, like a major project, while you knock off smaller items within it. You can start a meanwhile task with doing meanwhile Working on the @ACME job, optionally with a --back 2h, and then next time you run doing meanwhile it will finish that task, even if it wasn’t the last thing added. Starting a meanwhile task always finishes any currently-running “meanwhile”.

You can finish your last task with doing done (with no entry text), or doing finish, both of which accept both --back and --took. Supply a count with finish to finish the last X tasks, i.e. doing finish 5. One useful feature of finish is the --auto flag which will go through the last X entries and add finish times to each one based on the start time of the next one. It comes in handy.

Similar to the doing finish --auto trick, if you use -f (--finish_last) with the now command, it will check the previous item and see if it’s been tagged @done yet. If not, it will finish the previous entry with a timestamp matching the start time of the new item. When you’re in a mode where you’re logging each task as you start it, rather than retroactively (as I often do), this feature just allows you to skip the step of completing a task before starting a new one.

All of the view commands can show how long tasks took. In the default views, any task that has an interval between its start and end times will show a HH:MM:SS token at the end of the task. This can be modified in the various templates. Running a view or show command with --totals will add up total times by tag, and you can use --only_timed with the show command to only output entries with elapsed times.

Tagging and Time Tracking

Total times are displayed by tag. Adding a project tag allows you to see how much time went into each project. You can have multiple tags, of course, so you can have three different project tags but all of them get a @coding tag, so you can see each project but also a total for time spent in the coding context.

When it comes to tagging projects for time tracking, there are a couple of approaches. First, you can just manually add a tag to denote what the time should be attributed to, and you can overlap tags as needed. But you can automate this by using a “local” .doingrc file in your project directory. Configuration files found anywhere between the current directory and the root are applied on top of the main configuration, cascading such that the closest one takes precedence. Only the keys you want to override are needed.

For example, in the directory for Marked development (~/Code/Marked) there’s a .doingrc file that just contains:

---
default_tags: [marked]

And one in the parent directory (~/Code) with:

---
default_tags: [coding]

Any entry I make from the Marked directory (or any of its subdirectories) will get tagged “@marked @coding” automatically.

You can also tag the last task retroactively using doing tag TAGNAME. Or just run doing open and edit the file directly.

Autotagging

Autotagging in doing consists of “whitelisting” and “synonyms”. The synonyms feature is pretty cool: you can add a tag and then list all of the keywords that should trigger that tag. If a keyword appears in an entry, that tag gets added automatically.

The whitelist, on the other hand, is a list of words that should be directly turned into tags. If the list contains “design” and I type “Working on site design,” that gets converted to “Working on site @design.” Whereas if I had “design” set up with synonyms which include “typography,” I could write “Working on site typography” and it would become “Working on site typography @design.” Handy.

Automatic tags will never be repeated within an entry, so if you manually tag any of the defined tags it will skip adding them, and only the first occurrence of a keyword is converted into a tag.

Time Reporting

You can include time intervals in any template or view using the %interval template key. If a project has no time between the start and finish timestamp then nothing will display. This is great for seeing how much time you’ve put into things over the day.

To get a real report you can use doing show or doing view with --only_timed and --totals. With the show command you can use --from to specify a date or date range, and then provide @tags to show only the time spent on a specific project within a specific range.

Any project or activity you have a tag for is easily reported. An example command would look like:

doing show -t --totals --from="saturday to sunday" @writing

This gives me a report of what I’ve spent my time writing about this weekend. In this case, it’s all about this post. It will show all of the pertinent entries, with a block at the end containing totals for each tag and total elapsed time. Here’s what the above results look like for the weekend:

--- Tag Totals ---
doing:   00:02:15
writing: 00:02:15

Total tracked: 00:02:15

The more tags you have, the more detailed and flexible the reporting results are. And, as with any of the views, you can output this to nicely formatted HTML by adding -o html to the command.

By having overarching project tags as well as tags for various contexts like @designing, @coding, @writing, it’s easy to see how much total time went into a project, as well as exactly where the time was allocated. You can tag for anything. And if you make good use of the autotagging features, most of the work is done automatically.

Side note, when I forget to add a doing entry but wished I had, I load up Timing.app and am able to see what files I had open, when, and for how long. It’s the other half of my “too-scatterbrained-for-time-tracking” time tracking system.

Even More Natural Language

I’ve created a few aliases and functions as doing shortcuts over the years, but it’s all pretty simple. A verb with a function that specifies a section or adds tags, etc. Something as simple as alias thinking="doing now -s Ideas Thinking " means I can type thinking about digging back into React again and have that added to my Ideas list.

You can also use a wrapper function to handle all kinds of natural language. Here’s an example for Bash:

# Allows commands like `im coding bash scripts for doing`
im() {
	local verb=$1

	shift

	# special handling for `im thinking ...`
	if [[ $verb == "thinking" ]]; then
		# trim about
		[[ $1 == "about" ]] && shift
		# Add to Ideas with @idea tag
		doing done -s Ideas "$* @idea"
	# Special handling for `im coding ...`
	elif [[ $verb == coding ]]; then
		# Add to Projects with @coding tag
		doing now -s Projects "$* @coding"
	# Any other "ing" gets the verb tagged
	elif [[ $verb =~ ing$ ]]; then
		doing now "@$verb $*"
	# `im done ...` or `im finished ...`
	elif [[ $verb =~ (done|finished) ]]; then
		# If the first word after done is a present-tense
		# verb, tag it
		if [[ $1 =~ ing$ ]]; then
			doing done "@$*"
		else
			doing done "$*"
		fi
	# Fine, be boring
	else
		doing now "$*"
	fi
}

Working with entries

The beauty of the whole system is that you can open the doing file in your text editor or in TaskPaper at any time to make quick work of modifying your entries. You can specify an editor app in your .doingrc and then run doing open at any time to open the file.

In an effort to make things simpler, though, doing includes commands for flagging entries, archiving them, and batch moving them between sections. Want to archive everything in your Ideas section, keeping only the last three? doing archive --keep=3 Ideas. The archive command also accepts --to=[Section] to move entries to a section other than Archive. You can also specify a @tag to archive or move entries matching a tag, rather than just the last entries chronologically.

Automating

I won’t dig deep on automating, but I’ll point out that I’ve had great results using git hooks to update doing. You’ll also find scripts for LaunchBar and Alfred, as well as Bash, Fish, and Zsh completion on the project page. Whether it’s GeekTool, browser pipes with bcat, LaunchBar, or just the terminal, doing is designed to work with other tools as much as possible.

doing LaunchBar Action
doing LaunchBar Action

Phew

That got long, and it’s just an overview — I didn’t even cover all of the features. Or this is just the rantings of a madman. Hard to say sometimes. As mentioned previously, the documentation is complete and the built-in help system is verbose enough to fill in any gaps.

Like Marked 2, SearchLink, Reiki, na, or any of my pet projects, doing is one of my babies. I use it every day, and I bend it to fit my needs as they arise. I don’t need a large user base or an influx of donations to make it worthwhile, it’s fun to work on and I find it consistently useful. That said, feel free to try it out!

  1. Which is kind of a litmus test: if the idea of using git log is familiar, doing is probably for you. If not, probably not…

  2. I’m back to GeekTool after a long run with Übersicht. As much as I love writing my widgets in HTML and JavaScript, I just ran into too many bugs.

Brett Terpstra

Brett is a writer and developer living in Minnesota, USA. You can follow him as ttscoff on Twitter, GitHub, and Mastodon. Keep up with this blog by subscribing in your favorite news reader.

This content is supported by readers like you.

Join the conversation