Skip to main content

Minimal todo CLI for the terminal. Pure Python, zero dependencies.

Project description

tsk

PyPI Python Dependencies

A small task manager for the terminal. One line to add a task, one file to keep them in, and nothing to configure.

tsk adding three tasks, listing them, and completing a repeating one

uv tool install tsk-todo

Or try it without installing anything: uvx --from tsk-todo tsk

Why you might like it

There is nothing to set up. No config file, no theme to pick, no coefficients to tune. It works the way it works, and the first thing you do with it is add a task.

You can predict the order. Due date, then priority, then id. That is the entire rule. Nothing computes a score behind your back, so a task never jumps the queue for a reason you cannot see.

It repeats properly. Finish a daily task a week late and the next one is due tomorrow, not eight overdue copies waiting to be dismissed one at a time.

It stays out of the way. tsk add email bob@example.com about the invoice does exactly what you meant. So does tsk add fix the -v flag. Nothing gets swallowed as metadata.

You can leave whenever. Your tasks are one JSON file you can read, diff and commit. Stop using tsk tomorrow and they are still sitting there in a format anything can open.

Install

Needs Python 3.11 or newer, and nothing else. There are no runtime dependencies.

uv tool install tsk-todo

The command is tsk. The package is tsk-todo, because tsk on PyPI belongs to something else. pip install tsk-todo works too, and from a clone it is uv tool install .

The idea

You type what you mean and tsk works out which parts are metadata:

tsk add renew the passport @admin +boring due:eom p:h

@admin is the project, +boring is a tag, due:eom is the end of this month, p:h is high priority. Everything left over is the task itself.

Only due:, p: and every: are read as attributes, so ordinary text stays ordinary:

$ tsk add email bob@example.com about the invoice
$ tsk add fix the -v flag
$ tsk add ticket: replace the boiler

None of those pick up a project, a tag or an attribute. If it is not a form tsk knows, it is part of the description.

Commands

tsk                        list pending tasks
tsk add <text> [attrs]     add a task
tsk done <id>...           complete tasks
tsk rm <id>...             delete tasks
tsk edit <id> <attrs>      change a task
tsk note <id> <text>       attach a note
tsk show <id>              show one task in full
tsk list [filters]         list tasks

tsk 3 on its own is shorthand for tsk show 3.

done and rm take several ids at once: tsk done 2 5 9.

Attributes

Use these when adding or editing.

@project      set the project
+tag          add a tag
-tag          remove a tag, when editing
due:<when>    set a due date
p:h|m|l       set priority, high medium or low
every:<how>   reschedule on completion

Priority also accepts the full word, so p:high and p:h are the same.

Editing changes only what you name. Everything else is left alone.

$ tsk edit 3 due:friday +urgent
updated 3: read the book

To clear something, give it no value:

$ tsk edit 3 due: p: every:

A bare @ clears the project. A leading - removes a tag.

Filters

tsk +garden              tagged garden
tsk -work                not tagged work
tsk @home                in the home project
tsk overdue              past due
tsk due:friday           due on or before friday
tsk done                 completed tasks
tsk all                  everything
tsk plants               search descriptions and notes

Filters combine, and list is optional:

$ tsk @home +garden overdue
$ tsk list @work due:eow

Bare words search. tsk list dentist finds anything with dentist in the description or in a note.

Dates

Anywhere a date is wanted:

today, tomorrow, yesterday
monday .. sunday, or mon .. sun
3d, 2w, 1m, 1y
eow, eom, eoy
2026-08-01

Weekday names mean the next one coming. On a Thursday, due:thursday is a week away, not today.

Month and year offsets land on a real date. 1m from the 31st of January is the 28th of February, not the 3rd of March.

Due dates are plain calendar dates. due:friday means Friday wherever you happen to be, and it does not drift when you cross a timezone.

Repeats

every:daily
every:weekdays
every:weekly
every:monthly
every:yearly

A repeating task needs a due date. When you complete it, the next one is created for you:

$ tsk done 1
done 1: water the plants
  repeats as 5, due in 1 week

The next date is worked out from the old due date, then rolled forward until it is in the future. Finish a daily task five days late and the next one is due tomorrow, not last week. You never come back to a pile of overdue copies.

Notes do not carry over. The completed task keeps them.

Notes

$ tsk note 3 the ferns look worse than the rest
noted on 3: water the plants

Tasks with notes are marked with a * in the list. tsk show 3 prints them.

Ordering

Tasks sort by due date, then priority, then id. That is the whole rule. Nothing is scored or weighted behind your back, so the order is always one you can predict and explain.

Undated tasks sort last. They are not urgent, they are just there.

Your data

One JSON file, at ~/.local/share/tsk/tasks.json unless you say otherwise:

{
  "version": 1,
  "issued": 7,
  "tasks": [
    {
      "id": 2,
      "description": "fix the login bug",
      "status": "pending",
      "created": "2026-07-16T14:49:48+00:00",
      "project": "work",
      "tags": ["urgent"],
      "due": "2026-07-15",
      "priority": "high"
    }
  ]
}

Set TSK_DATA to put it somewhere else, or XDG_DATA_HOME to move the lot. Keep it in a git repo if you want history. Tags are written in a fixed order and absent fields are left out, so diffs stay small.

Writes are atomic. The file is written beside itself and then moved into place, so an interrupted write cannot leave you with half a file. Existing permissions are preserved.

Ids are never reused. Once id 3 has been handed out, no later task gets it, even if you delete task 3 the same day. The id you read a minute ago is still the task you thought it was.

Colour

On when writing to a terminal, off when piped. Set NO_COLOR to turn it off entirely.

Overdue is red, due today is yellow, projects are cyan, tags are magenta.

What it does not do

There is no urgency score, no dependency graph, no user defined attributes, no hooks, no custom report definitions and no sync. Each of those either failed the question "would I miss this" or costs far more than it returns for a tool this size.

If you want a task on the calendar, due: is where it goes. If you want to find it later, tag it. That is most of task management.

Development

uv sync
uv run pytest
uv run ruff check .
uv run ruff format .
uv run mypy

The suite runs in well under a second. It is worth keeping it that way.

Licence

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tsk_todo-0.1.2.tar.gz (12.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tsk_todo-0.1.2-py3-none-any.whl (15.8 kB view details)

Uploaded Python 3

File details

Details for the file tsk_todo-0.1.2.tar.gz.

File metadata

  • Download URL: tsk_todo-0.1.2.tar.gz
  • Upload date:
  • Size: 12.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for tsk_todo-0.1.2.tar.gz
Algorithm Hash digest
SHA256 4bec97faca3743547e04b409a59012ba51031677a27b8391926a001e7890ffa8
MD5 3a2aed0128b726da567bbc5883dd1892
BLAKE2b-256 411a5e02b70e1f09dafbb0b46d8f45da736c7382c29bffd42555050dba681298

See more details on using hashes here.

File details

Details for the file tsk_todo-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: tsk_todo-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 15.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for tsk_todo-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 2df44a31207bf892bedc2a1723c172667ce9bb93d0542b5db056eadd84baf6ba
MD5 365da0f18ab4d9eae2a379aba4da5126
BLAKE2b-256 80cd0250e0cbdcc2a16af7edaccf5a115539a291abef867ca656ae2815704afc

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page