t = parse_todo("(A) 2024-01-15 Call Mom @phone +Family due:2024-01-20")Todo: (A) 2024-01-15 Call Mom @phone +Family due:2024-01-20
Todo.txt is a plain-text format for managing tasks. Each line represents one task with an optional structure:
x (A) 2024-01-16 2024-01-15 Description @context +project key:value
│ │ │ │ │ │ │ │
│ │ │ │ │ │ │ └─ metadata
│ │ │ │ │ │ └─ project tag
│ │ │ │ │ └─ context tag
│ │ │ │ └─ description
│ │ │ └─ creation date
│ │ └─ completion date
│ └─ priority (A-Z)
└─ completion marker
All parts are optional except the description.
Use parse_todo to parse a single line and parse_todos for multiple lines:
Todo: (A) 2024-01-15 Call Mom @phone +Family due:2024-01-20
The parser extracts each component into a dedicated field:
Note that description contains only the plain text – contexts, projects, and metadata are stored separately:
Completed tasks start with x and may include a completion date:
The Todo constructor accepts a description string and keyword arguments. Tags embedded in the description are automatically extracted:
Todo: (B) 2024-01-15 Buy groceries @store +Errands
If you pass explicit contexts, projects, or metadata keyword arguments, they override extraction from the description:
write_todo serializes a Todo back to a single Todo.txt line. Tags are written in canonical order: description, contexts (@), projects (+), then metadata (key:value sorted by key).
"(A) 2024-01-15 Call Mom @phone +Family"
write_todos joins multiple tasks with newlines:
Read and write Todo.txt files directly:
# Write to a file
todos = [
Todo("Call Mom @phone +Family"; priority='A', creation_date=Date(2024, 1, 15)),
Todo("Pay bills"; completed=true, completion_date=Date(2024, 1, 16)),
Todo("Buy groceries @store +Errands"),
]
path = tempname()
write_todos(path, todos)
# Read it back
loaded = read_todos(path)
loaded == todostrue
Parsing and writing are inverse operations – a roundtrip preserves all data:
Tags in the original line may be reordered to canonical order (contexts, then projects, then sorted metadata). If the original line already follows this order, the roundtrip produces an identical string.