For context on how my brain works, see Working with an AuDHD Brain.

This is the stack that structures my daily work: taskwarrior for task management, timewarrior for time tracking, and vit as a vim-style interface. Together they form a keyboard-first, terminal-native productivity system.

No Electron apps. No cloud sync sending your data to Silicon Valley. Just plain text, local, and blazing fast.

Why This Stack?

I struggled with task management for years. Todoist, Things, Notion, Obsidian plugins — tried them all, eventually abandoned them all. The problem was always the same: too much friction.

Taskwarrior solves this:

  • Speed: Add a task in < 1 second
  • Keyboard-only: No mouse needed
  • Scriptable: Integration with everything
  • Offline: Works always, everywhere
  • Plain text: Your data is yours

Installation

macOS

brew install task timewarrior vit

Linux (Debian/Ubuntu)

sudo apt install taskwarrior timewarrior
pip install vit  # or via package manager

Arch Linux

sudo pacman -S task timew vit

After installation, run task once to create the config:

task version
# Creates ~/.taskrc and ~/.task/

Taskwarrior Basics

Adding Tasks

# Simple task
task add "Review pull request"

# With tags
task add "Fix login bug" +urgent +backend

# With due date
task add "Report delivery" due:friday

# With project
task add "Write API endpoint" project:acme.api

# All together
task add "Deploy to production" project:acme.api +urgent due:tomorrow priority:H

Viewing Tasks

task list              # All pending tasks
task                   # Same as task list (or task next)
task all               # Including completed and deleted
task completed         # Only finished tasks
task +urgent           # Filtered by tag
task project:acme      # Filtered by project

Managing Tasks

task 1 done            # Mark as done
task 1 delete          # Delete
task 1 modify +tag     # Add tag
task 1 modify due:monday  # Change due date
task 1 edit            # Open in $EDITOR
task 1 info            # All details

Starting/Stopping Tasks

task 1 start           # Mark as "active"
task 1 stop            # No longer active
task +ACTIVE           # View active tasks

Projects

Projects in taskwarrior use hierarchical notation with dots:

# Project structure
task add "Something" project:client.project.subproject

# Examples
task add "Design API" project:acme.api
task add "Write tests" project:acme.api.backend
task add "Build UI" project:acme.api.frontend

Viewing Projects

# All tasks in a project (including subprojects)
task project:acme list

# Only specific project
task project:acme.api list

# Project summary
task projects

Context (Project Focus)

Contexts automatically filter your view:

# Define context
task context define work "project:acme or project:byteherder"
task context define acme "project:acme"

# Activate context
task context acme
# Now 'task list' only shows acme tasks

# View context
task context show

# Disable context
task context none

This is exactly what my p function does — see my time-system scripts for the full implementation.

Dependencies

Tasks can depend on each other:

# Task 2 depends on task 1
task 2 modify depends:1

# Multiple dependencies
task 3 modify depends:1,2

# When creating
task add "Deploy" depends:1,2

Blocked Tasks

# View what's blocked
task blocked

# View what's unblocked (ready to do)
task unblocked

# View the dependency chain
task 1 info
# Shows: "blocking: 2, 3" and "blocked by: (none)"

Example Workflow

task add "Design database schema"           # Task 1
task add "Build API endpoints" depends:1    # Task 2
task add "Frontend integration" depends:2   # Task 3
task add "Write tests" depends:1            # Task 4
task add "Documentation" depends:2,3,4      # Task 5

task list
# ID Dep Description
#  1     Design database schema
#  2   1 Build API endpoints      [blocked]
#  3   2 Frontend integration     [blocked]
#  4   1 Write tests              [blocked]
#  5 2-4 Documentation            [blocked]

task 1 done
# Now tasks 2 and 4 are unblocked

task list
# ID Dep Description
#  2     Build API endpoints
#  3   2 Frontend integration     [blocked]
#  4     Write tests
#  5 2-4 Documentation            [blocked]

Tags

Tags are flexible labels:

# Adding
task add "Something" +urgent +backend +review

# Filtering
task +urgent list
task +backend +review list    # AND
task +backend or +frontend    # OR
task -urgent                  # NOT (exclude)

# Remove tag
task 1 modify -urgent

Useful Tag Conventions

+next        # Next to do
+urgent      # High priority
+waiting     # Waiting on someone else
+review      # Needs review
+blocked     # Manually blocked (besides depends)
+quick       # < 15 minutes

Priorities

# Three levels: H(igh), M(edium), L(ow)
task add "Critical fix" priority:H
task add "Nice to have" priority:L

# Modify
task 1 modify priority:M

# Filter
task priority:H list

Due Dates

Taskwarrior understands natural language:

# Specific
task add "Meeting" due:2026-01-30
task add "Deadline" due:2026-01-30T14:00

# Relative
task add "Soon" due:tomorrow
task add "This week" due:friday
task add "In a week" due:1week
task add "End of month" due:eom
task add "In 3 days" due:3d

# Recurring
task add "Weekly review" due:monday recur:weekly
task add "Standup" due:tomorrow recur:daily until:2026-12-31

Viewing by Due Date

task due:today list      # Today
task due.before:friday   # Before friday
task overdue             # Past due
task +OVERDUE            # Same

Reports

Taskwarrior has built-in reports:

task list         # Default list
task next         # Next tasks (smartly sorted)
task ready        # Ready to do (unblocked, not waiting)
task blocked      # Blocked by dependencies
task waiting      # Waiting on something
task recurring    # Recurring tasks
task completed    # Finished
task all          # Everything

Custom Reports

In ~/.taskrc:

# Minimal list
report.minimal.columns=id,description
report.minimal.labels=ID,Description
report.minimal.filter=status:pending

# Then: task minimal

Timewarrior Integration

Timewarrior automatically tracks time when you start/stop tasks.

Manual Tracking

timew start "coding" +projectX    # Start tracking
timew stop                        # Stop
timew                             # Current status
timew summary                     # Today
timew summary :week               # This week
timew summary :month              # This month

Taskwarrior Hook

Create automatic integration:

# ~/.task/hooks/on-modify.timewarrior
#!/usr/bin/env python3
import json
import subprocess
import sys

old = json.loads(sys.stdin.readline())
new = json.loads(sys.stdin.readline())

if 'start' in new and 'start' not in old:
    project = new.get('project', 'untagged')
    tags = new.get('tags', [])
    subprocess.run(['timew', 'start', project] + tags)

if 'start' in old and 'start' not in new:
    subprocess.run(['timew', 'stop'])

print(json.dumps(new))
chmod +x ~/.task/hooks/on-modify.timewarrior

Now task 1 start automatically starts time tracking!

Timewarrior Reports

timew summary :day              # Today
timew summary :week             # This week
timew summary 2026-01-20 - today  # Range
timew tags                      # All tags
timew summary :week project:acme  # Filtered

Correcting Time

# Adjust current tracking
timew modify start -30min       # Started 30 min earlier

# Adjust historical entry
timew summary :ids              # Find ID
timew modify @1 start 09:00     # Adjust start
timew delete @1                 # Delete entry

Vit: Vim Interface for Taskwarrior

Vit is a TUI with vim keybindings. Perfect if you have vim muscle memory.

Starting

vit                    # Default view
vit project:acme       # Filtered view
KeyAction
j / kUp / down
ggGo to beginning
GGo to end
Ctrl+d / Ctrl+uHalf page down/up
/Search
n / NNext/previous match

Task Actions

KeyAction
aAdd task
eEdit task (in $EDITOR)
mModify (inline)
dDone
DDelete
sStart/stop
uUndo
EnterTask info

Modify Examples

Press m and type:

project:acme              # Set project
+urgent                   # Add tag
-waiting                  # Remove tag
due:friday                # Set due date
depends:1                 # Add dependency
priority:H                # Set priority

Switching Views

KeyView
1next
2list
3completed
4blocked
5-9Custom reports

Command Mode

KeyAction
:Type task command directly
:qQuit
:!commandShell command

Example: :project:acme +urgent filters live.

Vit Config

~/.vit/config.ini:

[vit]
default_keybindings = vi

[report]
default_report = next

[color]
color = on

My Daily Workflow

I’ve packaged all my aliases, functions, and scripts into a reusable collection: time-system

# Install
git clone https://github.com/kapott/time-system.git
cd time-system && ./install.sh
source ~/.zshrc

Project-Based Workflow

The scripts expect a two-level directory structure for projects:

~/Documents/Git/           # TASKFUNC_PROJECTS_DIR
├── clientA/
│   ├── project1/
│   └── project2/
├── clientB/
│   └── projectX/

Daily Flow

# Morning
p                        # Select client/project with fzf
                         # -> cd's to directory
                         # -> sets taskwarrior context
                         # -> shows pending tasks
vit                      # View tasks in TUI

# Working
tstart                   # Pick task with fzf, starts timer
# ... work ...
tstop                    # Stop task + timer

# Throughout the day
tadd "New task"          # Adds to current project (or inbox if no scope)
tpl                      # List tasks for current project
tnext                    # What's next?

# End of day
dayend                   # Summary: completed, time tracked, still active

Key Commands

CommandDescription
pSelect project, cd to dir, set scope
tstart [id]Start task + timer (fzf if no id)
tstopStop current task + timer
tadd <desc>Add task to current project
tdone [id]Complete task (fzf if no id)
tplList tasks for current project
tctxnClear project scope
weekstartWeekly review
dayreviewDaily review
dayendEnd of day summary
twcurrentCurrent tracking status

See the full command reference for all aliases and functions.

Backup

Tasks live in ~/.task/:

# Simple backup
cp -r ~/.task ~/.task-backup-$(date +%Y%m%d)

# Or with git
cd ~/.task && git init && git add -A && git commit -m "Backup"

Advanced Features

UDAs (User Defined Attributes)

Custom fields:

# In ~/.taskrc
uda.estimate.type=duration
uda.estimate.label=Est

# Usage
task add "Big job" estimate:2h
task estimate.over:1h list

Urgency Tuning

Taskwarrior calculates urgency automatically. Tune it:

# ~/.taskrc
urgency.user.tag.urgent.coefficient=5.0
urgency.user.tag.quick.coefficient=2.0
urgency.blocking.coefficient=8.0
urgency.blocked.coefficient=-5.0

Taskd: Sync Server

If you use taskwarrior on multiple machines (laptop, desktop, server), you want synchronization. That’s what taskd is for — the official taskwarrior sync server.

Why Taskd?

  • Multi-device sync: Same tasks on all your machines
  • Conflict resolution: Taskwarrior handles merge conflicts
  • Offline-first: Works locally, syncs when possible
  • Self-hosted: Your data stays yours

Alternatives

Before setting up taskd, consider the alternatives:

OptionComplexityAdvantage
SyncthingLowSimple, sync entire ~/.task folder
GitLowVersion control, but no real sync
TaskdMediumOfficial, proper merge handling
Taskchampion Sync ServerMediumNewer, for Taskwarrior 3.x

For most people Syncthing is the easiest option. Taskd is for when you want proper sync with conflict resolution.

Installing Taskd Server

Via Package Manager

# Debian/Ubuntu
sudo apt install taskd

# Arch
sudo pacman -S taskd

# macOS (as server, unusual)
brew install taskd
# docker-compose.yml
version: '3'
services:
  taskd:
    image: andir/taskd
    ports:
      - "53589:53589"
    volumes:
      - ./taskd-data:/var/taskd
    environment:
      - CERT_CN=taskd.example.com
      - CERT_ORGANIZATION=MyOrg
docker-compose up -d

Server Configuration

If you install taskd manually:

# Create data directory
export TASKDDATA=/var/taskd
sudo mkdir -p $TASKDDATA
sudo chown $USER:$USER $TASKDDATA

# Initialize
taskd init

# PKI setup (certificates)
cd /usr/share/taskd/pki  # or where your pki scripts are
./generate

# Copy certificates
cp client.cert.pem $TASKDDATA
cp client.key.pem $TASKDDATA
cp server.cert.pem $TASKDDATA
cp server.key.pem $TASKDDATA
cp server.crl.pem $TASKDDATA
cp ca.cert.pem $TASKDDATA

# Configure server
taskd config --force client.cert $TASKDDATA/client.cert.pem
taskd config --force client.key $TASKDDATA/client.key.pem
taskd config --force server.cert $TASKDDATA/server.cert.pem
taskd config --force server.key $TASKDDATA/server.key.pem
taskd config --force server.crl $TASKDDATA/server.crl.pem
taskd config --force ca.cert $TASKDDATA/ca.cert.pem
taskd config --force server localhost:53589
taskd config --force log /var/log/taskd.log
taskd config --force pid.file /var/run/taskd.pid

Organizations, Groups and Users

Taskd has a hierarchical structure:

# Create organizations
taskd add org Work
taskd add org Home
taskd add org Freelance

# Groups within organizations (optional)
taskd add group Work backend-team
taskd add group Work devops-team

# Users per organization
taskd add user Work tom
taskd add user Work jan
taskd add user Home tom
# Output: New user key: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
# SAVE THIS KEY!

Important Nuance: No Shared Tasks

Here’s a common misunderstanding: taskd is not meant for sharing tasks between users.

Each user has their own, separate task database. Tom’s tasks are invisible to Jan — even if they’re in the same organization.

What taskd IS for:

  • Tom syncs his own tasks between laptop, desktop and phone
  • Jan does the same with his own devices
  • They share the server infrastructure, not the data

What taskd is NOT for:

  • Shared projects
  • Team task management
  • Assigning tasks to colleagues

Workarounds for team tasks:

OptionHowDownside
Shared accountEveryone uses same credentialsNo audit trail, who did what?
Export/importtask export | ssh colleague task importManual, no real sync
Different toolVikunja, Kanboard, PlaneNot taskwarrior

My advice: Use taskwarrior for personal tasks, and a dedicated tool for teamwork. Don’t try to make taskd do something it wasn’t designed for.

Generating Client Certificates

cd /usr/share/taskd/pki
./generate.client username

# This creates:
# - username.cert.pem
# - username.key.pem

Copy to your client machine:

  • ca.cert.pem
  • username.cert.pem
  • username.key.pem

Configuring Taskwarrior Client

On every machine where you want to sync:

# Place certificates in ~/.task
cp ca.cert.pem ~/.task/
cp username.cert.pem ~/.task/
cp username.key.pem ~/.task/

# Configure in ~/.taskrc
task config taskd.certificate ~/.task/username.cert.pem
task config taskd.key ~/.task/username.key.pem
task config taskd.ca ~/.task/ca.cert.pem
task config taskd.server taskd.example.com:53589
task config taskd.credentials 'MyOrg/username/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'

Starting Server

# Foreground (for testing)
taskdctl start

# As systemd service
sudo systemctl enable taskd
sudo systemctl start taskd

Synchronizing

# First sync (push everything to server)
task sync init

# Normal sync
task sync

Automatic Sync

You can automate sync with hooks or cron:

# ~/.task/hooks/on-exit-sync (automatically after every task action)
#!/bin/bash
task sync
chmod +x ~/.task/hooks/on-exit-sync

Or more conservatively with cron:

# Sync every 30 minutes
*/30 * * * * /usr/bin/task sync >> /tmp/tasksync.log 2>&1

Checking Sync Status

task sync                    # Sync and show status
task diagnostics | grep -A5 Sync  # View sync config

Troubleshooting Taskd

“Certificate fails validation”

# Check if certificates are correct
openssl verify -CAfile ~/.task/ca.cert.pem ~/.task/username.cert.pem

“Could not connect to server”

# Check if server is running
nc -zv taskd.example.com 53589

# Check firewall
sudo ufw allow 53589/tcp

“Sync conflict”

Taskwarrior handles most conflicts automatically. If there are problems:

task sync     # View conflict messages
task list     # Check if data is correct

Syncthing as Alternative

If taskd is too complex, Syncthing works fine:

# Install Syncthing on both machines
# Sync the ~/.task folder
# Done

# Downside: no real merge, last write wins
# Advantage: works for everything, not just taskwarrior

For my setup I use Syncthing for ~/.task. Simple and works.

Troubleshooting

“No matches”

# Check your context
task context show

# Clear context
task context none

Task disappeared?

task all                 # View everything
task status:completed    # Check completed
task status:deleted      # Check deleted

Undo

task undo               # Undo last action

Conclusion

Taskwarrior + timewarrior + vit isn’t the easiest setup. There’s a learning curve. But once you’re used to it, it’s unbeatable in terms of speed and flexibility.

The combination of:

  • CLI for quick actions
  • Vit for overview
  • Timewarrior for tracking
  • Scripts for your own workflow

…gives you a system that does exactly what you want, without compromises.

Start small. Learn the basics. Add complexity as you need it.

And if it doesn’t work for you — no problem. But for me this is the setup that stays.

task add "Learn taskwarrior" +next due:today
task 1 start

Good luck.