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
mascot: public-domain woodcut, wikimedia commons
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.
task add, task 3 done, task +work list, attribute modifiers, boolean filters, ID ranges, /regex/.urgency.* coefficients.rc.key=value overrides, color rules, aliases, contexts, UDAs.See the full feature matrix against Taskwarrior — including the honest list of gaps — in docs/parity.md.
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)
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.
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.