# Dailist

![logo](assets/logo.png)

An executive list task manager GUI based on todo.txt

<a href="https://dailist.ser1.net">Dailist</a> © 2025 by <a href="https://ser1.net">Sean E. Russell</a> is licensed under <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a> <img src="https://mirrors.creativecommons.org/presskit/icons/cc.svg" width="20px" height="20px" style="max-width: 1em;max-height:1em;margin-left: .2em;"><img src="https://mirrors.creativecommons.org/presskit/icons/by.svg"  width="20px" height="20px" style="max-width: 1em;max-height:1em;margin-left: .2em;"><img src="https://mirrors.creativecommons.org/presskit/icons/nc.svg"  width="20px" height="20px" style="max-width: 1em;max-height:1em;margin-left: .2em;"><img src="https://mirrors.creativecommons.org/presskit/icons/sa.svg"  width="20px" height="20px" style="max-width: 1em;max-height:1em;margin-left: .2em;">


[![Build status](https://builds.sr.ht/~ser/dailist/.build.yml.svg)](https://builds.sr.ht/~ser/dailist/.build.yml?)
★ [Releases](https://downloads.ser1.net/software/dailist/)
★ ![Latest release](https://downloads.ser1.net/software/dailist/badges/latest_release.svg)
  
★ [Changelog](https://hg.sr.ht/~ser/dailist/browse/CHANGELOG.md?rev=tip)
★ [Software metrics](https://downloads.ser1.net/software/dailist/badges/METRICS.md)
★ [Issues](https://todo.sr.ht/~ser/dailist)
★ [Mailing List](https://lists.sr.ht/~ser/dailist)
★ [Credits](https://hg.sr.ht/~ser/dailist/browse/CREDITS.md?rev=tip)  
[![Go Report Card](https://goreportcard.com/badge/ser1.net/dailist)](https://goreportcard.com/report/ser1.net/dailist)
★ ![Code linting](https://downloads.ser1.net/software/dailist/badges/linting.svg)
★ ![Code security](https://downloads.ser1.net/software/dailist/badges/vulnerabilities.svg)
★ ![Markdown linting](https://downloads.ser1.net/software/dailist/badges/doc_linting.svg)
★ ![Unit tests](https://downloads.ser1.net/software/dailist/badges/unit_tests.svg)  
![Code coverage](https://downloads.ser1.net/software/dailist/badges/coverage.svg)
★ ![Code complexity](https://downloads.ser1.net/software/dailist/badges/complexity.svg)
★ ![ABC metrics](https://downloads.ser1.net/software/dailist/badges/abc_score.svg)
★ ![Lines of code](https://downloads.ser1.net/software/dailist/badges/loc.svg)

- [Features](#features)
- [Usage](#usage)
- [Install](#install)
- [To-do & known bugs](https://hg.sr.ht/~ser/dailist/browse/CHANGELOG.md#todo?rev=tip)

![](assets/screenshot.png)

The idea for this program evolved from a [Substack essay by David
Maciver](https://drmaciver.substack.com/p/using-a-list-to-manage-executive)
about using todo lists. That's what it is in a nutshell, but there's more to it.
Read the article if you want depth; the short version is:

- To-do lists can be overwhelming. The grow faster than they're completed, become filled with OBE tasks[Overcome By Events]{.sidenote}, and can themselves become impediments to making progress.
- Executive lists are mini-lists just for today.
- Every day you create a brand-new, empty list. You put things in it that you _could_ make progress on today.
- Critical is that they're _ephemeral_. Executive lists must not exist past one day. You _must_ throw them away at the end of the day.
- Also important is that you always put more things in the list than you know you can accomplish today -- but _only_ things you _could_ do today.

The trick to executive lists is psychological: the nature of how you use them
make them not overwhelming. You don't worry about the list, because after today,
it's gone! You don't worry about doing everything on the list because you
**intentionally** filled it with more things you know you can accomplish.

"But wait!", I hear you cry. "I put things in to-do lists so I don't forget
about them. Throwing the list away would mean those things are lost." That's
where Dailist comes in.

**Note: please do not submit vibe-coded patches.** I'll feel bad about you spending
time submitting it, but I'll reject it. Thanks.


## Verifying assets

Assets are signed with [minisign](https://github.com/jedisct1/minisign). My key is [here](https://ser1.net/.well-known/minisign/ser.pub).


## Modified process

David doesn't address this specifically; there's a bit of hand-waving about "doing it your own way," which is fine. This is my way. Here's the paper version:

1. Have 2 little notebooks. One is the Big, Horrible, Infinite, Never
   Completable List of things you have to put on paper or else they nag at you.
   Things you don't want to forget, but can't do right now. The second is an
   Executive List. Every page is a day.
2. Start your morning by scanning the BHINCL and writing things down on the
   Executive List -- pick things it's _possible_ for you to work on today. This is
   your opportunity to break Big Items into smaller, completable items: "Paint the
   house" might become "Paint the bedroom." Put in more than you have time for, but
   don't go crazy. Depending on your lists, there might be 4-12 items on this list.
   It shouldn't be a huge chore to copy things over.
3. Do things on your Executive List. Should you get close to completing your
   list, go back to your BHINCL and copy over a couple more things.
4. If you need to add more things, **add them to the NHINCL first**, and if you
   can also do it today, add it to the executive list, too. Never, ever, only add
   things to the Executive list.
5. At the end of the day, go back and cross out in your BHINCL everything you
   completed today.
6. Go to bed satisfied that you Completed Things. Repeat the next day.

I love handwriting, but I do not enjoy copying text from one place to another.
Also, paper isn't searchable or filterable. Finally, unlike many people, I do
not get an endorphin rush from crossing things off lists; crossing things off
the BHINCL might just be desert to a list-crosser-off-er, but it's just tedious
to me. Also, I've long been a big fan of [todo.txt](http://todotxt.org/), so all
of my lists are digital, and I [wrote a series of fzf bindings and shell
scripts](https://hg.sr.ht/~ser/ddt/browse/tdp/README.md?rev=tip) to manage and
sync executive and big todo lists. This is fine for me; I'm happiest in a shell,
but it did not work for my wife, who needed a GUI.

dailist is that GUI. It's better than my shell scripts, because it manages both
scripts at the same time whereas my fzf bindings communicate only through the
lists: I can add stuff to the executive list, and if I cross things out on
either list I have to remember to refresh the other list. There's no real
communication between the programs.

dailist manages all that, and does the synchronization for you.


## Features

On top is a list box for the executive list. That starts each day empty. On the
bottom is the BHINCL. These lists are automatically loaded and all operations
that affect tasks in both lists are automatically synced.

- Blindingly fast
- Reasonably small (although not optimized for size)
- Native GUI (_not_ an SPA masquerading as a native app)
- Two "new task" entry fields; use the top one and the task is added to both the
  EL and the BHINCL. Use the bottom one and the task is added only to the BHINCL
- You can copy tasks from the BHINCL to the EL with the click of a button; this
  is a _copy_, not a _move_.
- Tasks deleted from the EL are _only_ deleted from the EL. That's for when you
  realize "there's no way I'm getting to this thing today."
- Tasks deleted from the BHINCL are completely deleted, from both lists if
  necessary.
- Checking a task as "completed" marks it complete in both lists, regardless of
  where it's checked.
- Unchecking similarly marks a task as "uncompleted" in both lists.
- Clicking on the task text lets you edit the text; the result modifies both
  tasks.
- Deleting a task from the EL only removes it from the EL; deleting a task in
  the BHINCL deletes it in both.
- Clicking the space between the lists toggles between giving most of the space
  to EL or to BHINCL. For example, you might start out with the BHINCL large,
  and then toggle to the EL being dominant after you've populated the EL.
- All changes are auto-saved, to both lists (if applicable): there's no "save"
  or "load" button.
- *Note* this feature has been troublesome and is currently disabled.
  {-A really basic conflict resolution, for when your file syncing system updates
  the todo files in the background. Right now, it only correctly handles
  task completions and task additions; removals will generally be undone,
  and attributes (+project, @context, due: and other tags) just get all
  mashed together. It's generally mostly OK if you're syncing often and
  don't change the same tasks in two locations. This is a sort of MVP;
  more intelligent merging will have to wait until I fix
  [todotxt-merge](https://hg.sr.ht/~ser/todotxt-merge), which has issues.-}
- The file format is just a todo.txt file. Right now, dailist does not add any
  todo.txt features, such as priorities or metadata annotations; however, it
  _should_ preserve them if your BHINCL contains them. It will _not_ copy them
  to your executive list, as that information is superfluous for the EL. In any
  case, you can use an existing todo.txt as your BHINCL, or in fact work with
  the BHINCL using todo.txt tools.

This last point is important, because there are many programs that also use
todo.txt. For example, I can sync my BHINCL to my phone with
[SyncThing](https://syncthing.net/) and work with it using
[Simpletask](https://github.com/fleapower/simpletask-android).[Although, see the
note below about building for Android]{.sidenote}


### Caveats

dailist isn't a comprehensive todotxt manager. There are many good tools for
that already. It's specifically targetted at helping you manage Executive Lists.
Consequently:

- Only the list text is shown. You won't see context, project, tags, or even
  priorities.
- There are no archive or sorting functions.
- The only way to choose the Big List that you're working with is to set
  `$TODO_FILE` or `$TODO_DIR`, which of course doesn't help Android users. But
  that's a moot point, because:
- as I say elsewhere, Gioui doesn't provide an interface to Android's constant
  buggery of file handling, so lists can't be synced.
- There's no undo function, so if you accidentally delete a task from the
  main list, it's gone.

Some of these items are in the roadmap; see the end of the
[Changelog](https://hg.sr.ht/~ser/dailist/browse/CHANGELOG.md?rev=tip) for a
complete list. I can't say if or when I'll get to any specific item;
bugs, and properly handling conflicts are probably the top of my list.


## Usage

By default, the application uses environment variables `TODO_DIR` and/or
`TODO_FILE`, if they are set; otherwise, it uses `~/.todo/todo.txt` (on Unix-y
systems, like Linux and OSX, and wherever Windows thinks `$HOME` is). This can
be changed by setting the environment variable `TODO_DIR` before running the
program. If you happen to be running this on a mobile device with Ubuntu Touch
or Phosh, you can set `TODO_DIR` in your `~/.profile`, and it should get
picked up after the next time you restart your session (just like any Linux).


## Install

[Releases](https://downloads.ser1.net/software/dailist/) are available for
platforms for which they can be made. If you would like me to add a target,
[drop me a note](https://lists.sr.ht/~ser/dailist). I can **not** create builds for
MacOS, because gioui requires Xcode from Apple and I can't put that in the CI.
Or maybe there's a way, but I don't care to figure it out. There are builds for
some Linux architectures, Windows amd64 (is _anyone_ trying to run Windows on
ARM?), and Android. It's easier to cross-compile GUI apps for Android than
MacOS. That's boggles the mind.

There is a build system; that's what all the `*.do` files are. There are three
main targets:

- `redo`: the default "all"
- `redo furios`: which builds an Linux arm64 deb package (see the section on
  cross-compiling for arm64 before attempting this one; it requires setting up).
- `redo android`: which builds an Android apk. Which will probably fail because
  it references a signing keystore which is not in the repos.
- `redo release`: which signs the packages and uploads them to my release server.
  It will not work for you, unless you are me. If you fork the repos and want
  to use this thing, you _can_ -- you just need to change some of the secrets.

There's a Secrets section below that talks about everything needed for signing,
for forkers and for myself when I inevitably mess something up and have forgotten
how I set it all up in the first place.


### Steps

- Build the executable, using the appropriate section below
- Copy the executable `dailist` (or `dailist.exe` on Windows) in your
  path
- On Linux

  - Copy `assets/dailist.desktop` into `~/.local/share/applications`
    directory
  - Copy `assets/dailist.svg` into `~/.local/share/icons`
  - Go to your launcher and look for "dailist", and run it
  
- If you're on Linux amd64 and want to cross-compile it for Linux arm64,
  for your FLX1s Linux phone, for instance, use the build system and
  instructions below


### Native, for your current desktop

Compiling it yourself is straightforward. You need Mercurial to check out the
project (or just download the tarball). You also need Go to compile it. The
project relies on [gioui](https://gioui.org), which has few dependencies, but
the first compile can take a long time because it's linking into X and Wayland
libraries. While takes longer than usual for Go programs, it's still as easy as
running `go build -o dailist ./cmd/dlg` in the project directory, and being
patient. 

For Go enthusiasts, I have not tried `go install ser1.net/dailist@latest`.
It _might_ work? Gioui is a freaking _awesome_ library, but it does add
some twists.


### Cross-compile for Android

dailist can be built for, and runs on, Android. You will need to install the JDK, the
Android SDK and Android NDK, and the
[gogio](https://pkg.go.dev/gioui.org/cmd/gogio) command. Getting Java and the
Android SDK and NDK set up on your machine is highly dependent on your
distribution. You'll also need:

- [gogio](https://git.sr.ht/~eliasnaur/gio-cmd):

  ```
  go install gioui.org/cmd/gogio@latest
  ```

- [cairosvg](https://cairosvg.org), or [svg2png](http://cairographics.org/), or
  any tool which can convert SVG to PNG.

Once you can build Android apps, the easiest way to build an apk is to run `redo
android`. If you want to manually walk through the steps, here's what `redo` is
doing:

1. The icon needs to be in PNG format; Android wants it to be 48x48 image:

   ```
   cairosvg --output-width 48 --output-height 48 -b white -o android.png assets/dailist.svg
   ```

2. To compile, I use this command (the version doesn't really matter since it
   doesn't make it into the actual asset):

   ```
   gogio -target android -buildmode exe -icon android.png -o dailist-0.0.1.apk .
   ```

3. Assuming you can plug your phone into your computer, tell your phone to let the
   computer control the phone then install the apk with `adb`:
   
   ```
   adb install dailist-0.0.1.apk
   ```

Or, copy the apk to your phone and install it from the file browser. It looks
just and functions just like the desktop.


### The build system

The build system is [redo](https://redo.readthedocs.io/en/latest/redo/). It's
the best way to build for arm64 on amd64 easier. redo is what all the `.do`
files are for; each is a target -- if you want to see all the targets:

```bash
$ find . -name \*.do
```

The `default-` ones are meta-targets, but you can try the others. `redo all`
tries to do everything. 


### Pre-compiled executables

In the [Releases](https://downloads.ser1.net/software/dailist/) directory
_might_ be RPMs, debs, apk, and what not for various distros. Because of
Sourcehut's inability to cross compile for arm64, CI usually fails and I
haven't yet taken the time to make it smart enough to work around that.

One thing I do do is manually build arm64 Debian packages; I do this for my
Furilabs FLX1s, where I test and run Dailist. FuriOS is based on Phosh
Debian/forky, so the package might work on any other Linux phones such as Ubuntu
Touch. If you have issues, reach out to me on the [Mailing
List](https://lists.sr.ht/~ser/dailist) and I'll see what I can do. Download it,
verify the signature, then run `dpkg -i dailist_X.Y.Z-R_arm64.deb`.


#### Signatures

Pre-compiled binaries will usually have signatures from my public keys. `.sig`
are PGP signatures, `.minisig` are minisign. You can get my public signing key
from Sourcehut, where it's used for the automated builds. For minisign, you can
get it from [https://ser1.net/.well-known/minisign/ser.pub](https://ser1.net/.well-known/minisign/ser.pub).


### Mac (iOS/OSX/Darwin)

I do not have a Mac or Windows machine; the gioui docs say that `gogio` can be
used to cross-compile for other platforms, but if you're building _on_ one of
those machines, I suspect `go build` will work.


### Cross-compiling (and arm64) (FuriOS/FLX1(s))

Cross-compiling across OSes is, ironically, easy; cross-compiling across
architectures is not, due to the amount of CGO from Gioui.

`gogio` takes care of cross-compiling for Android, but compiling from
Linux/amd64 -> Linux/arm64 requires linking to system libraries. Some
distributions make it easy to install multiple architectures on the same
machine. Another way is to use qemu and a container. There are instructions
online for getting podman set up to cross-compile for different distributions;
for Arch:

1. Install and link QEMU

   ```bash
   $ pacman -S qemu-user-static qemu-user-static-binfmt
   $ sudo podman run --rm --privileged docker.io/multiarch/qemu-user-static --reset -p yes
   ```

   The second command must be run as sudo, as the container creates symlinks to
   binaries in the qemu packages which will be available to containers.

2. Create a cross-compile builder container using the `Containerfile`:

   ```sh
   podman build --platform linux/arm64 -t armbuilder -v ${PWD}:/workspace .
   ```

   This may take a while to build. The image only needs to be built once.

3. At this point, you should really try the `redo furios` command and it should
   build you a `.deb`. But if you don't want to, then

4. The image can be run (repeatedly) with
   
   ```sh
   podman run --platform linux/arm64/v8 -v ${PWD}:/workspace armbuilder
   ```

   or, to set the version number and strip the executable, you can run `-it`:

   ```sh
   podman run -it --rm --platform linux/arm64/v8 -v ${PWD}:/workspace armbuilder \
      go build -x -v -ldflags "-X main.Version=v0.0.8 -s -w" -o build/linux_arm64 ./cmd/dlg
   ```

   Note that you want the binary to have that name and location if you're going
   to use nfpm to build a deb package. However, you _could_ just copy that executable
   onto your phone and run it from a terminal. It won't have the icon or show up
   in the launcher.

4. If you're putting this on, say, a Phosh phone, the nfpm file will build an
   installable deb that includes an icon and application launcher for your
   launcher:
   
   ```bash
   $ VERSION=0.0.6 RELEASE=2 nfpm pkg -p deb
   ```

## Secrets

- GPG signatures (`default.sig.do`) require only changing the default key in the `.do` file,
  and probably a running gpg-agent. Or it might prompt for the password.
- Minisig (`default.minisig.do`) require minisig to be installed, and changing the signature
  file path in the `.do`. Or not, if you happen to store your signature in exactly the same
  place I do.
- Android (`default.apk.do`) requires changing the keystore path and key
  password in the `.do`. The dofile uses [rook](https://sr.ht/~ser/rook) to
  fetch the keystore password, but that can be replaced with whatever secret
  server CLI command you use. Or, if the keystore is unsigned, you can just
  remove the `-signpass` line.
- Releasing (`release.do`) copies files over ssh. ssh itself will ask for a password or
  use your running ssh-agent, but you'll probably just want to completely change this.
  I used to upload it via webdav, but it required several more lines of script, and ssh
  was just simpler; use whatever works for you.
