Ben Crowder / Blog

Liszt intro

First in the series introducing my personal productivity tools. Buckle up, this is going to be nerdy. And long.

Liszt is my to-do list app. Named after the composer, though I regret it a little since I butcher his name by pronouncing it lisht to differentiate it from the ordinary list. Heresy. The next version will have a better name, though. It’s a Python app running on Django.

Disclaimer: I don’t think this app is perfect. (Or any of the other tools I’ll talk about, for that matter.) I’ll describe things as they are, acknowledging here that there’s a lot of room for improvement.

Overview

This is what the dashboard looks like, populated with some dummy data:

liszt-1.png

And on mobile, where the controls move to the bottom for easier access:

liszt-1mobile.png

The top bit is my stats panel, with the data pulled in from my other tools’ APIs. Daily writing counts, daily words left, total words written on the novel (all three from Storybook), daily pages left (from Bookshelf), and daily goals left (from Momentum). I’ll cover those tools later.

There’s also a slide-in menu on the side, with my most commonly used top-level lists:

liszt-2.png

Double-clicking on a list item opens up an edit panel, which also allows me to move the item to another list with some commonly used lists included as buttons (this whole panel is kind of clunky and needs improvement):

liszt-7.png

Payload syntax

The basic idea behind Liszt (and this is common to many of my apps) is the text-based payload, which enables some nice cross-app integrations (more on this when I cover Gate and Quill). Adding items looks like this:

liszt-3.png

A Liszt payload (the text entered into the add tray) has one item per line, with optional blank lines and optional list specifiers. If there’s no specifier, it’ll assume the current list if there is one, otherwise it’ll default to ::inbox. (I use the double-colon prefix to mark lists, with a slash to specify sublists.) Here’s a fuller example of the syntax, again with dummy data:

Process email :5
Review the merge requests :10

::work/notifications
Read up on Python futures ::: https://docs.python.org/3/library/concurrent.futures.html
Refactor [::work/notifications/refactor]
Write up the design doc

The first two items (which have belt-mode durations, I’ll explain those in a minute) would go into the ::today list (which is the dashboard list). The last three items would go into the ::work/notifications list, as pictured here:

liszt-3b.png

Of these, the first line sets a subtitle by putting it after the triple-colon marker. I use this all the time.

The second line is a symlink of sorts, pulling in the top item from the linked list (different meaning here) and showing it in place, with the Refactor text shown as the subtitle. I used to use this more often but haven’t as much lately.

You can also see that this list has a child list (::work/notifications/refactor).

Belt mode

liszt-4.png

If an item has a duration marker included, that triggers belt mode (ala conveyer belts), as evidenced by the new bar at the top of the screen in the image above.

Brief backstory: I initially wrote an Electron app called Belt that did the same sort of thing, then a few months ago ported it to Go as a menubar app. Shortly after I finished that, I realized it would make much more sense in Liszt and brought the functionality in.

And what is that functionality? It’s just an easy way to time tasks from the list. When I hit Start, it switches into belt mode (also changing the favicon so I can tell that it’s running and turning on focus mode so I can only see the task I’m actively working on):

liszt-5.png

When the timer runs out, it plays a sound and brings up a panel allowing me to continue on to the next item in the list, stop belt mode, or add more time to the timer. (There are also keyboard shortcuts for all of this.)

liszt-6.png

How I use Liszt

On my laptop, I have Liszt open in Firefox as a pinned tab. On my phone, I have it saved to my homescreen as a PWA.

Every morning I go through the main lists and move the items I’m going to work on to the today list. I then work out of the today list the rest of the day, opening it often.

I use belt mode most days, primarily to help me stop avoiding tasks I don’t really want to work on (but that still need to be done).

The future

Lately I’ve grown enamored of the idea of storing data as plain text files in directories, rather than using an actual database like Postgres or Mongo. There are plenty of apps where this doesn’t make sense, but for personal, small tools, it works nicely, so I’m planning to migrate Liszt off SQLite to plain text, and I am very excited about it. Yes, I am that kind of a person.

While Django is fine (we use it at work and I love it), I’m planning to move to FastAPI, which I’m already using for Ditto and Arc. It’s a bit faster and feels more lightweight. I think in my mind I mostly use Django because of the ORM and admin; once I’ve given that up, the baby goes out with the bathwater.

I’m also looking forward to simplifying things, removing vestigial functionality, and sanding down as many of the friction points as I can.