· · 14 min leestijd Beginner

Taskwarrior, Timewarrior en vit: de ultieme CLI productiviteit stack

Complete tutorial voor taskwarrior, timewarrior en vit. Van basics tot geavanceerd: projecten, dependencies, time tracking, taskd sync server, en vim-style task management.

Een terminal met taakkaarten en een stopwatch, één toets verplaatst een kaart, een plakbriefjesmonster stort in

TL;DR Taskwarrior, timewarrior en vit zijn mijn takenlijst, mijn timetracking en het vim-scherm erbovenop, allemaal in de terminal en allemaal plain text in ~/.task. Met twee commando’s ben je begonnen. De rest van deze post is wat ik er later aan vastschroefde, van projecten en dependencies tot een sync-server op eigen hardware, en je mag bij elke sectie afhaken.

Voor context over hoe mijn brein werkt, zie Werken met een AuDHD-brein.

Mijn hele productiviteitssysteem past in twee regels:

task add "Intro schrijven" +next
task 1 start

Meer is het niet. De taak staat genoteerd, de klok loopt, en dat gebeurde allebei binnen een seconde zonder dat ik de muis aanraakte. De stack eronder is taskwarrior voor taken, timewarrior voor tijd, en vit als vim-scherm bovenop de eerste. Toetsenbord eerst, en plain text op schijf.

Geen Electron-apps. Geen cloud-sync die m’n data naar een vendor stuurt waar ik niet in kan kijken. De bestanden staan in ~/.task en ze zijn van mij.

Waarom deze stack

Met taskmanagement heb ik jaren gevochten. Todoist, Things, Notion, een stapel Obsidian-plugins. Allemaal geprobeerd, allemaal weer weggedaan, en de reden was elke keer dezelfde. Een gedachte uit m’n hoofd in de tool krijgen duurde langer dan de gedachte zelf.

Voor mijn brein is dat het hele probleem. Kost een taak opschrijven me drie clicks en een laadspinner, dan wordt hij niet opgeschreven. Een laadspinner voor een takenlijst, daar word ik sowieso niet vrolijk van. Taskwarrior doet het gewoon binnen een seconde, zonder muis, offline zonder server, het haakt in op elk script dat ik wil schrijven, en de data staat in bestanden die ik met elke editor open kan doen.

Zit er een addertje onder het gras? Er is een leercurve, en de eerste week voelt onhandig. Volgens mij heb je dat binnen een paar dagen wel terugverdiend. De rest van deze post is alles wat ik aan die twee regels heb toegevoegd, van task add tot een sync-server die ik zelf host.

Installatie

macOS

brew install task timewarrior vit

Linux (Debian/Ubuntu)

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

Arch Linux

sudo pacman -S task timew vit

Draai na het installeren even één keer task, dan maakt hij de config aan:

task version
# Maakt ~/.taskrc en ~/.task/ aan

Toevoegen, bekijken, aanpassen, starten

Taken toevoegen

# Simpele task
task add "Review pull request"

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

# Met due date
task add "Oplevering rapport" due:friday

# Met project
task add "API endpoint schrijven" project:acme.api

# Alles samen
task add "Deploy naar productie" project:acme.api +urgent due:tomorrow priority:H

Taken bekijken

task list              # Alle pending tasks
task                   # Zelfde als task list (of task next)
task all               # Inclusief completed en deleted
task completed         # Alleen afgeronde tasks
task +urgent           # Gefilterd op tag
task project:acme      # Gefilterd op project

Taken beheren

task 1 done            # Markeer als klaar
task 1 delete          # Verwijderen
task 1 modify +tag     # Tag toevoegen
task 1 modify due:monday  # Due date wijzigen
task 1 edit            # Open in $EDITOR
task 1 info            # Alle details

Taken starten en stoppen

task 1 start           # Markeer als "bezig"
task 1 stop            # Niet meer bezig
task +ACTIVE           # Bekijk actieve tasks

Projecten

Projecten in taskwarrior zijn hiërarchisch, met punten tussen de niveaus:

# Project structuur
task add "Iets" project:klant.project.subproject

# Voorbeelden
task add "API ontwerpen" project:acme.api
task add "Tests schrijven" project:acme.api.backend
task add "UI bouwen" project:acme.api.frontend

Projecten bekijken

# Alle tasks in een project (inclusief subprojecten)
task project:acme list

# Alleen specifiek project
task project:acme.api list

# Project summary
task projects

Contexts maken de lijst smaller

Een context is een filter die aan blijft staan tot je hem uitzet:

# Context definiëren
task context define werk "project:acme or project:byteherder"
task context define acme "project:acme"

# Context activeren
task context acme
# Nu toont 'task list' alleen acme tasks

# Context bekijken
task context show

# Context uitzetten
task context none

Dat is wat mijn p-functie doet. De volledige implementatie staat in mijn time-system-scripts.

Dependencies

Taken kunnen van elkaar afhangen:

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

# Meerdere dependencies
task 3 modify depends:1,2

# Bij aanmaken
task add "Deploy" depends:1,2

Geblokkeerde taken

# Bekijk wat geblokkeerd is
task blocked

# Bekijk wat unblocked is (klaar om te doen)
task unblocked

# Bekijk de dependency chain
task 1 info
# Toont: "blocking: 2, 3" en "blocked by: (none)"

Een uitgewerkt voorbeeld

task add "Database schema ontwerpen"           # Task 1
task add "API endpoints bouwen" depends:1      # Task 2
task add "Frontend integratie" depends:2       # Task 3
task add "Tests schrijven" depends:1           # Task 4
task add "Documentatie" depends:2,3,4          # Task 5

task list
# ID Dep Description
#  1     Database schema ontwerpen
#  2   1 API endpoints bouwen      [blocked]
#  3   2 Frontend integratie       [blocked]
#  4   1 Tests schrijven           [blocked]
#  5 2-4 Documentatie              [blocked]

task 1 done
# Nu zijn task 2 en 4 unblocked

task list
# ID Dep Description
#  2     API endpoints bouwen
#  3   2 Frontend integratie       [blocked]
#  4     Tests schrijven
#  5 2-4 Documentatie              [blocked]

Tags

Tags zijn labels die je gaandeweg verzint:

# Toevoegen
task add "Iets" +urgent +backend +review

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

# Tag verwijderen
task 1 modify -urgent

Tag-conventies

+next        # Volgende om te doen
+urgent      # Hoge prioriteit
+waiting     # Wacht op iemand anders
+review      # Moet gereviewd worden
+blocked     # Handmatig blocked (naast depends)
+quick       # < 15 minuten

Prioriteiten

Drie niveaus, en een vierde heb ik nog nooit gemist:

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

# Wijzigen
task 1 modify priority:M

# Filteren
task priority:H list

Due dates

Taskwarrior leest datums zoals je ze aan een collega zou typen:

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

# Relatief
task add "Binnenkort" due:tomorrow
task add "Deze week" due:friday
task add "Over een week" due:1week
task add "Eind van de maand" due:eom
task add "Over 3 dagen" due:3d

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

Bekijken op due date

task due:today list      # Vandaag
task due.before:friday   # Voor vrijdag
task overdue             # Te laat
task +OVERDUE            # Zelfde

Reports

Taskwarrior heeft voor elke vraag die je vaak stelt een report aan boord:

task list         # Standaard lijst
task next         # Volgende tasks (slim gesorteerd)
task ready        # Klaar om te doen (unblocked, niet waiting)
task blocked      # Geblokkeerd door dependencies
task waiting      # Wacht op iets
task recurring    # Herhalende tasks
task completed    # Afgerond
task all          # Alles

Eigen reports

Definieer je eigen in ~/.taskrc:

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

# Dan: task minimal

Timewarrior-integratie

Timewarrior houdt zelf tijd bij, en met één hook loopt hij mee met elke task start en task stop.

Handmatig bijhouden

timew start "coding" +projectX    # Start tracking
timew stop                        # Stop
timew                             # Huidige status
timew summary                     # Vandaag
timew summary :week               # Deze week
timew summary :month              # Deze maand

De taskwarrior-hook

Dit is de hook die de twee aan elkaar knoopt:

# ~/.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

Nu zet task 1 start ook de klok aan.

Timewarrior-reports

timew summary :day              # Vandaag
timew summary :week             # Deze week
timew summary 2026-01-20 - today  # Range
timew tags                      # Alle tags
timew summary :week project:acme  # Gefilterd

Tijd corrigeren

Klok vergeten te starten? Achteraf rechtzetten kan:

# Huidige tracking aanpassen
timew modify start -30min       # Startte 30 min eerder

# Historische entry aanpassen
timew summary :ids              # Vind ID
timew modify @1 start 09:00     # Pas start aan
timew delete @1                 # Verwijder entry

Vit, een vim-interface voor taskwarrior

Vit is een TUI met vim-keybindings. Kennen je vingers j, k en / al, dan heeft hij geen handleiding nodig.

Opstarten

vit                    # Standaard view
vit project:acme       # Gefilterde view
KeyActie
j / kOmhoog / omlaag
ggNaar begin
GNaar eind
Ctrl+d / Ctrl+uHalf page down/up
/Zoeken
n / NVolgende/vorige match

Taakacties

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

Modify-voorbeelden

Druk m en typ wat je achter task modify zou typen:

project:acme              # Zet project
+urgent                   # Voeg tag toe
-waiting                  # Verwijder tag
due:friday                # Zet due date
depends:1                 # Voeg dependency toe
priority:H                # Zet prioriteit

Views wisselen

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

Command mode

KeyActie
:Task command direct typen
:qQuit
:!commandShell command

:project:acme +urgent filtert de lijst live, bijvoorbeeld.

Vit-config

~/.vit/config.ini:

[vit]
default_keybindings = vi

[report]
default_report = next

[color]
color = on

Mijn dagelijkse workflow

Al mijn aliassen, functies en scripts staan in één repo, time-system:

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

Eén directory per project

De scripts verwachten twee niveaus aan directories, klant en daaronder project:

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

Een dag, van begin tot eind

# Ochtend
p                        # Selecteer client/project met fzf
                         # -> cd naar directory
                         # -> zet taskwarrior context
                         # -> toont pending tasks
vit                      # Bekijk taken in TUI

# Werken
tstart                   # Kies taak met fzf, start timer
# ... werk ...
tstop                    # Stop taak + timer

# Tussendoor
tadd "Nieuwe taak"       # Voegt toe aan huidig project (of inbox zonder scope)
tpl                      # Lijst taken voor huidig project
tnext                    # Wat is volgende?

# Eind van dag
dayend                   # Samenvatting: afgerond, tijd bijgehouden, nog actief

De commando’s die ik het meest gebruik

CommandoBeschrijving
pSelecteer project, cd naar dir, zet scope
tstart [id]Start taak + timer (fzf als geen id)
tstopStop huidige taak + timer
tadd <desc>Voeg taak toe aan huidig project
tdone [id]Rond taak af (fzf als geen id)
tplLijst taken voor huidig project
tctxnWis project scope
weekstartWekelijkse review
dayreviewDagelijkse review
dayendEind van dag samenvatting
twcurrentHuidige tracking status

De volledige command reference somt elke alias en functie op.

Backup

Alles staat in ~/.task/, dus een backup is een kopie:

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

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

Eigen velden en urgency

User defined attributes

Eigen velden, die taskwarrior UDAs noemt:

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

# Gebruik
task add "Grote klus" estimate:2h
task estimate.over:1h list

Urgency tunen

Taskwarrior rekent urgency zelf uit, en aan de coëfficiënten mag je draaien:

# ~/.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, de sync-server

Gebruik je taskwarrior op meer dan één machine, dan wil je dat ze het met elkaar eens zijn. Taskd is daar de officiële sync-server voor, en je host hem zelf, dus de data blijft op een machine die jij beheert.

Wat taskd je oplevert

Dezelfde taken op elke machine, merge-conflicts die taskwarrior zelf afhandelt, offline eerst met een sync zodra de server bereikbaar is, en een server die van jou is.

Alternatieven

Kijk eerst even naar de alternatieven voordat je taskd opzet:

OptieComplexiteitVoordeel
SyncthingLaagSimpel, sync hele ~/.task folder
GitLaagVersiebeheer, maar geen echte sync
TaskdMediumOfficieel, proper merge handling
Taskchampion Sync ServerMediumNieuwer, voor Taskwarrior 3.x

Voor de meeste mensen is Syncthing de makkelijkste optie. Taskd is voor als je een echte merge wilt in plaats van laatste write wint.

De taskd-server installeren

Via de package manager

# Debian/Ubuntu
sudo apt install taskd

# Arch
sudo pacman -S taskd

# macOS (als server, unusual)
brew install taskd

Docker (aanbevolen)

# 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

Serverconfiguratie

Installeer je taskd met de hand:

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

# Initialiseren
taskd init

# PKI setup (certificaten)
cd /usr/share/taskd/pki  # of waar je pki scripts staan
./generate

# Certificaten kopiëren
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

# Server configureren
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

Organisaties, groepen en gebruikers

Taskd is ingedeeld in organisaties, optioneel groepen, en gebruikers:

# Organisaties aanmaken
taskd add org Werk
taskd add org Thuis
taskd add org Freelance

# Groepen binnen organisaties (optioneel)
taskd add group Werk backend-team
taskd add group Werk devops-team

# Gebruikers per organisatie
taskd add user Werk tom
taskd add user Werk jan
taskd add user Thuis tom
# Output: New user key: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
# BEWAAR DEZE KEY!

Eén database per gebruiker, niks delen

Dit misverstand kom je vaak tegen, dus het krijgt z’n eigen kopje. Taskd deelt geen taken tussen gebruikers.

Elke gebruiker krijgt een eigen, gescheiden takendatabase. Toms taken zijn onzichtbaar voor Jan, ook binnen dezelfde organisatie. Wat taskd wél doet is Toms eigen taken laten syncen tussen laptop, desktop en telefoon, en Jan hetzelfde laten doen met zijn apparaten. Ze delen één server en verder niks.

Dus geen gedeelde projecten, geen taskmanagement voor het team, geen taak toewijzen aan een collega. Heb je dat toch nodig, dan zijn dit de omwegen:

OptieHoeNadeel
Gedeelde accountIedereen gebruikt dezelfde credentialsGeen audit trail, wie deed wat?
Export/importtask export | ssh collega task importHandmatig, geen echte sync
Andere toolVikunja, Kanboard, PlaneNiet taskwarrior

Mijn advies is taskwarrior voor je eigen taken en een aparte tool voor het team. Probeer taskd niet iets te laten doen waar het niet voor gebouwd is.

Client-certificaten genereren

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

# Dit maakt:
# - username.cert.pem
# - username.key.pem

Kopieer ca.cert.pem, username.cert.pem en username.key.pem naar de client-machine.

De taskwarrior-client configureren

Op elke machine die moet syncen:

# Certificaten in ~/.task plaatsen
cp ca.cert.pem ~/.task/
cp username.cert.pem ~/.task/
cp username.key.pem ~/.task/

# Configureren 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'

De server starten

# Foreground (voor testen)
taskdctl start

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

Synchroniseren

# Eerste sync (push alles naar server)
task sync init

# Normale sync
task sync

Automatisch syncen

Een hook synct na elk commando, cron synct op een schema. Eerst de hook:

# ~/.task/hooks/on-exit-sync (automatisch na elke task actie)
#!/bin/bash
task sync
chmod +x ~/.task/hooks/on-exit-sync

Of, wat voorzichtiger, cron:

# Elke 30 minuten syncen
*/30 * * * * /usr/bin/task sync >> /tmp/tasksync.log 2>&1

Sync-status checken

task sync                    # Sync en toon status
task diagnostics | grep -A5 Sync  # Bekijk sync config

Troubleshooting taskd

Zegt sync “Certificate fails validation”, check dan de certificaten tegen de CA:

# Check of certificaten correct zijn
openssl verify -CAfile ~/.task/ca.cert.pem ~/.task/username.cert.pem

Zegt hij “Could not connect to server”, check dan of de server draait en de poort open staat:

# Check of server draait
nc -zv taskd.example.com 53589

# Check firewall
sudo ufw allow 53589/tcp

De meeste “Sync conflict”-meldingen lost taskwarrior zelf op. Doet hij dat niet:

task sync     # Bekijk conflict meldingen
task list     # Check of data klopt

Syncthing als het alternatief

Is taskd je te veel, dan doet Syncthing het ook prima:

# Installeer Syncthing op beide machines
# Sync de ~/.task folder
# Done

# Nadeel: geen echte merge, laatste write wint
# Voordeel: werkt voor alles, niet alleen taskwarrior

Mijn eigen ~/.task synct over Syncthing. Simpel, en het werkt gewoon.

Troubleshooting

“No matches”

Meestal staat er nog een context aan:

# Check je context
task context show

# Clear context
task context none

Een taak die weg lijkt

Waarschijnlijk afgerond of verwijderd, en allebei staan ze nog op schijf:

task all                 # Bekijk alles
task status:completed    # Check completed
task status:deleted      # Check deleted

Undo

task undo               # Laatste actie terugdraaien

Twee commando’s zijn genoeg

Die twee regels bovenaan zijn nog steeds m’n hele systeem. Alles daarna, projecten, dependencies, de klok, vit, de sync-server, heb ik toegevoegd toen ik het miste, en elk stuk is optioneel.

Typ je nooit meer dan task add en task done, dan heb je een compleet systeem en dat houdt het jaren vol. Vit verdient z’n plek zodra de lijst niet meer op één scherm past, en timewarrior de eerste keer dat iemand vraagt waar je week gebleven is. De scripts komen als laatste, op de dag dat je het aan je eigen directories wilt knopen. Voeg elk stuk toe als je het mist.

Er is een leercurve, en dat ga ik niet ontkennen. De reden dat ik bij deze stack blijf is dat hij zich plooit naar hoe ik werk, in plaats van mij in andermans idee van een productiviteitsapp te duwen, en de data staat in plain text die ik beheer. Probeer je het en klikt het niet, ook prima. Bij mij is het gebleven.

Hier is je eerste taak:

task add "Taskwarrior leren" +next due:today
task 1 start