Skip to content

Latest commit

 

History

History
305 lines (214 loc) · 17.8 KB

File metadata and controls

305 lines (214 loc) · 17.8 KB

📋 taskwarrior.nvim

Edit your Taskwarrior database like a Neovim buffer. Every vim motion, macro, and visual-mode operation becomes a task management operation. Inspired by oil.nvim.

Latest release Last commit License Stars Issues

60-second tour: bulk-edit, quick capture, filter+group, fullscreen visualizations, guided review, live diff preview

✨ Features

  • 📝 Edit as markdown:Tw opens your Taskwarrior database as a buffer; every vim motion is a task operation
  • Quick capture from any buffer<leader>ta floats a one-line capture in any buffer
  • 🔍 Live query blocks in arbitrary markdown<!-- taskmd query: due.before:eow --> renders matching tasks below it on save; embed live task lists in your project's notes.md
  • 📊 Built-in visualizations — burndown, dependency tree, per-project summary, calendar, tag frequency, Mermaid graph
  • 🎯 Guided review + GTD inbox:TwReview walks pending tasks in urgency order; :TwInbox triages new captures
  • 🤖 Delegate to Claude:TwDelegate opens a popup form and runs the task as a Claude prompt in a bottom split
  • 🎓 Interactive tutor:TwTutor teaches Taskwarrior + the plugin from scratch in 20 minutes, fully sandboxed (your real ~/.task is never touched)

⚡ Requirements

  • Neovim ≥ 0.9
  • Taskwarrior ≥ 2.6 (compatible with 3.x)

📦 Installation

-- lazy.nvim
{
  "matthandzel/taskwarrior.nvim",
  config = function()
    require("taskwarrior").setup()
  end,
}

🚀 Quick start

:Tw                          -- view all pending tasks
:Tw project:career +ais      -- filter
:Tw due.before:eow           -- tasks due this week

Edit any line. :w to sync. That's it.

🎓 New to Taskwarrior? Run the tutor

:TwTutor

A 5-lesson, ~20-minute interactive walkthrough that teaches the Taskwarrior CLI. Fully sandboxed.

Prefer video? Andrew Dumont's Taskwarrior intro on YouTube is a great 5-minute primer; come back to :TwTutor after.


📸 Showcase — visualizations, quick capture, guided review, delegation, diff preview

Browse, filter, group

filter and group demo

:TwFilter project.startswith:work narrows to a project. :TwGroup project splits the buffer into ## sections. :TwSort due+ re-sorts within groups. None of this touches your Taskwarrior database — only the view.

Quick-capture from any buffer

quick capture demo

<leader>ta pops a floating window in any buffer. Type Fix auth bug project:work priority:H, press Enter, go back to what you were doing. The task is in Taskwarrior before your hand leaves the keyboard.

:TwBurndown — completion trend over time

burndown chart

ASCII bar chart of pending-task count by date. Reads entry and end dates from every task you've ever created, samples to fit the buffer width, color-codes by remaining height (red high → green low). Useful for "am I actually closing tasks faster than I'm opening them?"

:TwTree — dependency graph

dependency tree

Renders depends: relationships as an indented tree. Top-level tasks are roots; └── and ├── connectors show parentage. Urgency score on the right is color-coded (red ≥8, orange ≥4, green below). Dead-simple way to find the leaf tasks that are unblocking everything else.

:TwSummary — per-project stats

project summary

For each project: pending count, done count, overdue count, high-priority count, and a horizontal bar. Bar color is red if any task is overdue, orange if any is high-priority, blue otherwise. Footer shows total completion rate.

:TwCalendar — by due date

calendar view

Pending tasks grouped by due date, ordered chronologically. Today is marked ← TODAY, overdue dates marked ⚠ OVERDUE. Tasks under each date show priority (!H/!M/!L) and project (@name).

:TwTags — tag frequency

tags view

Every tag on every pending task with a count and frequency bar. Quick way to see which tags you're actually using vs. which were one-offs.

:TwReview — guided urgency walk

guided review walkthrough

Walks pending tasks in urgency order. For each task: k keep, d defer, D mark done, m modify, g jump to it in the main buffer, q quit. Useful for the "weekly tidy" pass where you want to look at every urgent task and decide what to do with it without opening a separate buffer.

:TwDelegate — hand a task to Claude

delegate popup

Opens a popup form (extra context, flags, model, system-prompt-file) and runs Claude in a visible bottom split. Visual-range support: V to select multiple task lines, then :TwDelegate delegates them all in one Claude session. :TwDelegate copy and :TwDelegate copy-command copy the assembled prompt or the full shell invocation to the + register without spawning anything.

:TwDiffPreview — see edits before you save

diff preview virt_text

Toggle with :TwDiffPreview on. As you edit, virtual-text labels appear at end-of-line: + ADD, ~ MODIFY, ✓ DONE, ✗ DELETE, ▶ START, ◼ STOP. 400ms debounce keeps it from running on every keystroke. Same data the :w confirmation dialog uses — just shown live.

Auto-project filter from cwd

Register the directories you work in:

:TwProjectAdd career      -- maps cwd to project:career
:TwProjectList            -- show all mappings
:TwProjectRemove          -- unmap cwd

After that, :Tw (with no filter) auto-applies project:<name> whenever you launch it from inside a registered directory. Persisted to stdpath("data")/taskwarrior_nvim_projects.json.

Ecosystem

These are bundled but require their own host plugins.

Module Path Activate
Telescope picker lua/telescope/_extensions/task.lua require("telescope").load_extension("task") then :Telescope task tasks
nvim-cmp source lua/taskwarrior/cmp.lua require("cmp").register_source("task", require("taskwarrior.cmp").new()) then add { name = "task" } to your cmp sources
Statusline component lua/taskwarrior/statusline.lua require("taskwarrior.statusline").render() — returns a string with the active task / overdue count / next due

All commands

Command Description
:Tw [filter] Open task buffer with optional Taskwarrior filter
:TwFilter [filter] Change filter on current buffer
:TwSort <spec> Change sort order (e.g. due+, urgency-, priority-)
:TwGroup [field] Change grouping (project, tag, or none)
:TwRefresh Reload from Taskwarrior
:TwAdd Quick-capture a task (floating window)
:TwUndo Reverse last save's changes
:TwHelp Show all commands, keybindings, syntax
:TwStart / :TwStop Start / stop active timer on task under cursor
:TwSave <name> / :TwLoad [name] Save / restore the current filter+sort+group as a named view
:TwReview Guided urgency walk through pending tasks
:TwDelegate [copy|copy-command] Delegate task(s) to Claude in a popup form
:TwDiffPreview [on|off|toggle] Toggle live virt-text diff preview
:TwBurndown Pending-task burndown chart
:TwTree Dependency tree
:TwSummary Per-project stats
:TwCalendar Tasks grouped by due date
:TwTags Tag-frequency view
:TwProjectAdd [name] / :TwProjectRemove / :TwProjectList Auto-project mapping
:TwTutor [reset] Open the interactive tutorial; reset ends an active session and cleans up orphan temp dirs
:TwFeedback [last-error] Open the structured bug-report form; last-error pre-fills with the most recent ERROR captured by the plugin

Keybindings (buffer-local)

Key Action
<CR> Toggle task complete/pending
o New task below
O New task above
dd Delete task (marks done on save by default)
yy + p Duplicate task
ga Add annotation
gf View formatted task info
<leader>ta Quick-capture (global, works from any buffer)
<leader>tt Open task buffer (global)
<leader>tf Change filter (in task buffer)
<leader>ts Change sort (in task buffer)
<leader>tg Change group (in task buffer)
<leader>tpa Register cwd as a project

Metadata syntax

Tasks use Taskwarrior-native syntax after the description:

- [ ] Fix login bug project:Work priority:H due:2026-04-01 +urgent +backend

Fields: project:, priority: (H/M/L), due:, scheduled:, recur:, wait:, until:, effort:, depends:

Tags: +tagname (supports hyphens: +my-tag)

UDAs: Custom fields are auto-discovered from your Taskwarrior config (task _udas) and serialized inline. Verified: render, edit, save round-trip on both backends.

Configuration

require("taskwarrior").setup({
  on_delete = "done",          -- "done" or "delete" when lines are removed
  confirm = true,              -- show confirmation dialog before applying
  sort = "urgency-",           -- default sort (field+ for asc, field- for desc)
  group = nil,                 -- default group field (nil to disable)
  fields = nil,                -- fields to show (nil = all)
  capture_key = "<leader>ta",  -- global quick-capture (nil to disable)
  open_key = "<leader>tt",     -- global open-task-buffer (nil to disable)
  filter_key = "<leader>tf",   -- buffer-local filter (nil to disable)
  sort_key = "<leader>ts",     -- buffer-local sort
  group_key = "<leader>tg",    -- buffer-local group
  project_add_key = "<leader>tpa",  -- register cwd as a project
  filters = {},                -- named filter presets (see :h)
  projects = {},               -- directory-to-project mapping
  icons = true,                -- nerd font checkbox/header icons
  border_style = "rounded",    -- "rounded" | "single" | "double" | "none"
  capture_width = nil,         -- quick-capture width (nil = auto)
  capture_height = 3,          -- quick-capture height in lines
  auto_backup = true,          -- copy ~/.task to stdpath("data")/taskwarrior.nvim/backups/ before apply
  auto_backup_keep = 10,       -- number of recent backups to retain
  delegate = {
    command = "claude",
    flags = "",                -- e.g. "--dangerously-skip-permissions" (opt-in)
    model = nil,
    system_prompt_file = nil,
    height = 0.5,
  },
})

Custom urgency with UDAs

Custom feature from taskwarrior.nvim!

If you have custom UDA fields (e.g. utility, effort) and want them to affect task sort order, use urgency_coefficients. For each field, the urgency adjustment is value × coefficient — proportional to the actual numeric value, not just whether the field is present:

require("taskwarrior").setup({
  urgency_coefficients = {
    utility = 1.0,     -- utility:8 adds +8, utility:20 adds +20
    effort = -0.5,     -- effort:60 subtracts -30 (do easy wins first)
  },
})

The default is {} (no adjustments) — set only the fields you use.

For non-linear urgency (e.g. log(utility) or utility / effort), use custom_urgency — a Lua function that receives the full task table and returns a number:

require("taskwarrior").setup({
  custom_urgency = function(task)
    local base = task.urgency or 0
    local utility = tonumber(task.utility) or 0
    local effort = tonumber(task.effort) or 60
    return base + math.log(utility + 1) * 3 - math.sqrt(effort) * 0.1
  end,
})

Health check

Run :checkhealth taskwarrior to verify your setup (Neovim version, Taskwarrior CLI, data directory).

Data safety

Status: Beta. Usable day-to-day, but APIs and defaults may still change. Always keep an external backup of your Taskwarrior data (cp -r ~/.task ~/.task.bak); review the confirmation dialog before saving — :w issues real task modify / task done / task delete commands.

:w issues real task modify / task done / task add / task delete commands against your Taskwarrior database. There is no staging.

By default (auto_backup = true), the plugin copies your Taskwarrior data directory to stdpath("data")/taskwarrior.nvim/backups/<timestamp>/ immediately before any apply. The ten newest backups are kept; older ones are pruned. Disable with auto_backup = false in setup().

Help

Run :help taskwarrior.nvim inside Neovim for the full reference, or read doc/taskwarrior.txt. :checkhealth taskwarrior verifies your setup.

Contributing

See CONTRIBUTING.md. Quick version:

./tests/lua/bootstrap.sh           # 380+ Lua assertions via plenary
./tests/e2e/run.sh                 # end-to-end against real `task` binary

Every bug fix needs a regression test. The Lua suite covers parser/diff/render/save and every user-facing command; the e2e suite drives features against a real task CLI and validates downstream output (mmdc for Mermaid, task export for mutations, window state for floats).

Changelog

See CHANGELOG.md.

License

MIT