# Why I Left Todoist for a Plain-Text TODO.md

- Canonical: https://matheja.me/2026/10/09/why-i-left-todoist-for-a-plain-text-todo-md.html
- Date: 2026-10-09
- Author: Ben Matheja
- Tags: productivity, todoist, obsidian, gtd, ai
- Site: Ben Matheja (https://matheja.me), llms.txt: https://matheja.me/llms.txt

I used Todoist from 2014 and even built my own webhook integration around it. In spring 2026 I moved every task into a single `TODO.md` at the root of my Obsidian vault. The file is synced with git, shown in my daily journal through one Dataview query, and edited by me and by AI agents alike.


## What my Todoist integration did

If you landed here looking for Todoist webhooks, the API or an integration, this part is for you.

In 2020 I wanted a reminder for the moment I had to leave the office. Zapier's free plan polled every 15 minutes and IFTTT needed a paid plan for my use case, so I wrote my own receiver. Todoist can call a URL whenever something happens to a task. I registered a webhook for `item:completed`, and a small [Flask](https://flask.palletsprojects.com/) app checked the completed task. When it was "Clock in", it created a "Clock out" task for the latest allowed time of the day. The full story, including the Gunicorn packaging pain, is in [Build your own Todoist Integration](https://matheja.me/2020/03/14/my-todoist-integration.html).

A few months later I moved the same handler to AWS Lambda with the Serverless framework and GitHub Actions for deployment. It ran in the free tier and got rid of the Nginx and Gunicorn layers. That is described in [Migrated my Todoist Integration to Lambda](https://matheja.me/2020/06/15/transform-todoist-integration-to-serverless.html). My original notes on the setup, plus a few Todoist habits, are in [How I'm using Todoist](https://matheja.me/2019/01/03/todoist-markdown.html).

The approach worked well: a webhook that fires on an event, a tiny handler, and the Todoist API to write something back. Two caveats if you want to rebuild it today. Both 2020 posts target an old version of the Sync API, and Todoist has deprecated it since. The current documentation is the [Todoist API v1](https://developer.todoist.com/api/v1/), which has a "Migrating from v9" section, so read that before copying any code from my old posts. The webhook payloads are signed with an HMAC header, so verify it in your handler. I have not rebuilt the integration against v1, so I cannot tell you how much of my old code survives.

## Why I stopped using Todoist

Todoist did not get worse. My setup got more complicated around it.

By early 2026 my tasks lived in Todoist, my context lived in daily journals and project notes, and my infrastructure issues lived in GitLab. Keeping those three in line became a job of its own. I once cross-checked a whole Todoist project against my project notes and the issue tracker, task by task, and created the tasks that were missing. Another time I copied open to-dos out of five journal entries into Todoist and marked the journals as moved. That is a copy, and copies drift.

At the same time I wanted AI agents to work with my tasks. I had connected Todoist to Claude and to OpenCode through MCP, and it worked, but only as long as authentication did. Once a sync stalled on an auth problem and the task just sat there as a note in my journal.

So in March I went through the whole list, about 133 tasks, and moved everything that lasted into my notes: wishlists, project files, area notes. What remained was a short list of real to-dos, and that became one file.

## A plain-text TODO.md with Dataview

The file is called `TODO.md`, lives at the root of the vault and is grouped by topic with plain Markdown headings:

```markdown
## Homelab

- [ ] Renew TLS cert for the NAS
- [ ] Add an alert for failed backups

## House

- [ ] Replace smoke detector batteries
```

My daily journal does not copy these tasks. It queries them with [Dataview](https://blacksmithgu.github.io/obsidian-dataview/):

````markdown
```dataview
TASK
FROM "TODO"
WHERE !completed
GROUP BY meta(section).subpath
```
````

Ticking a box in the journal ticks it in `TODO.md`, because the journal only shows a view. There is no carry-forward step in the morning and nothing to reconcile in the evening.

The rules I wrote for myself are short:

- **A checkbox is a title.** One line, roughly 120 characters at most. The journal renders the file as a task list, and a paragraph breaks that view.
- **Context lives somewhere else.** If an item needs more than a sentence, it becomes a project note or a knowledge note and the checkbox links to it.
- **A TODO says what and where to look, never how.** If I catch myself writing a rationale or a command into a checkbox, that text wants to be a note.
- **No inline checkboxes in journals.** New tasks go into `TODO.md`, nowhere else.

The old Todoist code blocks in my older notes are dead render blocks now, and I never create new ones.

## Plain text works for agents

This is the part I did not expect to like as much as I do. A Markdown file needs no API client, no token and no webhook. Claude Code and OpenCode read it the same way I do and edit it with the same tools they use for code.

My start-of-day routine reads `TODO.md` and surfaces anything with a date. My end-of-day routine reads it again, reports what was touched but not ticked, and prunes finished lines. Before it deletes a ticked item, it checks that the journal records the completion, so the journal stays the log and the file stays short. Everything is in git, so a wrong edit is one `git diff` away from being undone.

## What I gave up

I do not want to pretend this is a free upgrade. Todoist is better at several things:

- **Capture on the go.** Todoist's quick add is faster than opening a vault on a phone.
- **Natural-language dates and reminders.** "Every second Friday" simply works there. In a Markdown file a date is text. Appointments go into my calendar instead, which was already where I put anything with a time.
- **Sharing.** A shared shopping list with my partner is what Todoist does best. When I migrated, the shared shopping list stayed there, so "retired" applies to tasks, not necessarily to every list in my life.
- **Polish.** Filters, priorities and a clean mobile app are real work that I now do without.

What replaced them is Obsidian on the phone, with a small iOS Shortcuts automation that runs a full git pull, commit and push whenever the app opens or closes. It keeps the vault in sync and the merge conflicts rare, though not gone. Capture is slower than in Todoist, and I accept that.

## Should you switch?

If your tasks are mostly your own and you already keep notes in Markdown, a single file is worth trying for a month. If you depend on reminders, shared lists or a team, stay where you are. I left because I wanted one source of truth that people and agents can both edit, and I found it in a file that needs no integration at all, which is a little ironic for someone who wrote a Todoist integration.
