A tiny four-state task parser for Markdown task files. Track work in plain Markdown, query it like data.
Zero dependencies · MIT licensed · Python 3.10+
A Markdown checkbox is binary — done or not done:
- [ ] not done
- [x] doneBut real work has a gap between "I changed it" (done) and "I confirmed it actually works" (verified). Conflating those two is exactly how silent failures hide — you tick the box, move on, and never check the change actually did what you intended.
programme-parser keeps four states distinct: pending → in_progress → done → verified. done means the work happened; verified means it was confirmed. Only verified is truly complete.
That one distinction came out of years delivering infrastructure, where "installed" and "commissioned-and-signed-off" are very different things — and treating them as the same gets people hurt. The same discipline applies to software and AI systems: an unverified change is not a finished change.
pip install programme-parser # (when published)
# or, for now:
pip install -e .from programme_parser import parse, summary
content = """
# Sprint tasks
- [ ] T-101 · design the API
- [ ] T-102 · build it <!-- status: in_progress -->
- [x] T-103 · write tests
- [x] T-104 · deploy (status: verified) #release
"""
tasks = parse(content)
for t in tasks:
print(f"{t.task_id or '-':8} {t.status:12} {t.text}")
# T-101 pending design the API
# T-102 in_progress build it
# T-103 done write tests
# T-104 verified deploy
summary(tasks)
# {'pending': 1, 'in_progress': 1, 'done': 1, 'verified': 1}
# only T-104 is genuinely complete:
[t.text for t in tasks if t.is_complete] # ['deploy']
# T-103 is 'done' but NOT verified — the gap that matters:
[t.text for t in tasks if t.status == 'done' and not t.is_complete] # ['write tests']| Syntax | Result |
|---|---|
- [ ] text |
pending |
- [x] text |
done |
- [ ] text <!-- status: in_progress --> |
in_progress (annotation overrides checkbox) |
- [x] text (status: verified) |
verified |
- [ ] T-123 · text or [ABC-7]: text |
extracts task_id |
#tag anywhere |
collected into task.tags |
Non-task lines (headings, prose) are ignored. * bullets work as well as -.
parse(content: str) -> list[Task]parse_file(path: str) -> list[Task]summary(tasks) -> dict[str, int]— counts by state (counts everything, then you filter)Task—.text .status .task_id .line_no .tags .is_complete .is_open
pip install pytest && pytestMIT — see LICENSE.
One of a set of small tools extracted from systems I build as independent R&D. More at my profile.