taskpeasant — a peasant with a knife and a basket, from a public-domain woodcut

TASK / PEASANT

Taskwarrior logic, ported to Python — as close as we could get.
A YAML-native task engine for local-first apps and platforms where the Taskwarrior binary is unavailable — like native Windows.

pipx install taskpeasant

view on GitHub →

mascot: public-domain woodcut, wikimedia commons

Why

Taskwarrior is excellent — but it's a C++ binary, and on Windows it lives behind WSL or a brittle MSYS2 build.

If your app already speaks YAML and lives on the filesystem, you don't need any of that. Built by analogtrsh studio as the native task backend for Studio OS on Windows, taskpeasant re-implements the Taskwarrior model in pure Python — released GPL-3.0-or-later, the same license as Taskwarrior, whose open-source code is the reference for taskpeasant's behaviour, defaults, and output shape.

What it ports

See the full feature matrix against Taskwarrior — including the honest list of gaps — in docs/parity.md.

Quickstart

The CLI installs as tp (and taskpeasant). We deliberately don't claim the task name, so a real Taskwarrior install can coexist — alias task=tp completes the illusion if taskpeasant is the only task tool on the machine.

export TASKPEASANT_FILE=~/tasks/work.yaml

# the TW-style CLI parser returns plain text for your terminal widget:
print(execute_command("task add render the final shot +urgent due:tomorrow", yaml_path))
print(execute_command("task next", yaml_path))
print(execute_command("task +urgent export", yaml_path))   # TW wire JSON

# optional: hand it a config with custom reports / urgency / colors
conf = Taskrc({"report.kanban.columns": "id,project,description.desc",
               "report.kanban.filter": "+ACTIVE"})
print(execute_command("task kanban", yaml_path, config=conf))

# …or call the Python API directly:
cmd_add(yaml_path, "another task", tags=["render"], due="2026-06-25")
tasks = read_tasks(yaml_path)

Storage & config

taskpeasant reads and writes a single top-level key, taskpeasant_tasks:, inside any YAML file you point it at — it will never touch any other key, so you can embed it inside a file that already carries project metadata or config. The undo journal lives in a sidecar file (<file>.undo) for the same reason.

taskpeasant_tasks:
  - uuid: 8c2f1a3b-...
    description: render the final shot
    status: pending
    entry: 2026-06-19T14:30:00Z
    tags: [urgent]
    due: 2026-06-20T00:00:00Z

Config is a Taskwarrior-style taskrc, read from $TASKPEASANT_TASKRC, $TASKRC, ~/.taskpeasantrc, or $XDG_CONFIG_HOME/taskpeasant/taskrc. Everything can also be passed per-invocation as rc.key=value.

default.command=next
urgency.user.tag.next.coefficient=15.0
report.kanban.columns=id,project,description.desc
color.overdue=bold red
alias.rm=delete
context.work=+work
recurrence=on          # opt-in; read BACKWARDS_COMPAT.md first

Full storage contract in docs/storage.md and docs/BACKWARDS_COMPAT.md.

Status

Beta. Frozen contract.

The public API and storage contract are frozen and guarded by a test suite. Feature coverage against Taskwarrior is tracked openly — gaps and all — so you know exactly what you're opting into before you embed it.

pipx install taskpeasant

read the docs →