{"slug": "a-todo-txt-shared-by-a-human-and-ai-agents-why-plain-text-beat-a-saas-board-for", "title": "A todo.txt shared by a human and AI agents: why plain text beat a SaaS board for my workflow", "summary": "A developer replaced a SaaS task board with a plain-text todo.txt file that both they and their AI coding agents read and write. The file uses a simple format with priority, dates, project tags, and context tags, and is managed via a small CLI and cron job. The setup eliminates API dependencies and provides a shared surface for human-plus-agent workflows.", "body_md": "If you have tried to give an AI coding agent access to your task board, you have probably hit the wall I did: the board lives behind an API, and the agent lives in your repo. Here is the low-tech surface I use instead, where both of us read and write the same file.\n\nI maintain a fleet of small OSS projects. The cross-cutting \"what do I do next\" list used to live in my head, then in a SaaS board, then nowhere useful. What finally stuck is embarrassingly low-tech: a single `todo.txt`\n\nin [todo.txt format](http://todotxt.org/), plus a few dozen lines of dependency-free shell and Python around it.\n\nThe twist is that I'm not the only one reading and writing that file. My AI coding agents read it, grep it, and append to it too. Same file, same format, no API in between. This post is about why a plain-text board turned out to be the right shared surface for a human-plus-agents workflow, and what the moving pieces actually are.\n\n**What you'll learn:**\n\n`todo.txt`\n\nis a better shared surface for human-plus-agent work than a hosted boardThere are only three things, and the file is the important one.\n\n`todo.txt`\n\n— the source of truth\nEvery open task is one line. Priority in parentheses, a creation date, the description, a `+project`\n\ntag, an `@context`\n\ntag, and an optional `due:`\n\nin ISO format:\n\n```\n(A) 2026-01-10 add CSV export to the reports page +myapp @dev due:2026-01-15\n(B) 2026-01-09 write onboarding docs +docs-site @writing\n2026-01-08 investigate flaky auth test +myapp @dev due:2026-01-20\n```\n\nThat's the whole schema. `(A)`\n\n–`(C)`\n\nis priority (A first), `+project`\n\nnames the repo, `@context`\n\nis the kind of work (`@dev`\n\n, `@review`\n\n, `@ops`\n\n, `@writing`\n\n, ...), and `due:YYYY-MM-DD`\n\nis the deadline. Because dates are ISO, plain string comparison sorts them correctly — the sort itself needs no date parsing at all (relative dates like `due:+3d`\n\nare resolved to an absolute ISO date once, at write time).\n\nCompleted tasks don't clutter the board. A `done`\n\ncommand moves the line, prefixed with `x`\n\nand a completion date, into a separate `done.txt`\n\narchive.\n\nA tiny CLI (`todo.sh`\n\n— pure bash over coreutils; the gantt and issue views shell out to a small dependency-free Python script) is the front door:\n\n```\ntodo.sh                 # today: overdue + due-today + priority-A\ntodo.sh week            # deadlines within 7 days\ntodo.sh all             # everything, sorted by priority then due date\ntodo.sh ls +myapp       # filter by project or any substring\ntodo.sh add \"(A) add CSV export +myapp @dev due:+3d\"\ntodo.sh done \"CSV export\"\n```\n\nTwo conveniences that pull their weight: `add`\n\naccepts **relative due dates** — `due:today`\n\n, `due:tomorrow`\n\n, `due:+3d`\n\n, `due:+2w`\n\n, `due:fri`\n\n— and rewrites them to an absolute ISO date before saving, so the stored file stays unambiguous. And `add`\n\nstamps the creation date for you. The query and display path is mostly `grep`\n\n, `awk`\n\n, and `sort`\n\nover one text file.\n\nA single crontab line runs a `rollup`\n\ncommand once a night (22:00, in my case):\n\n```\n0 22 * * * /path/to/todo.sh rollup >> rollup.log 2>&1\n```\n\n`rollup`\n\nreads the board and writes a dated Markdown digest — `daily/2026-01-12.md`\n\n— with counts (open / overdue / due-today / this-week) and each bucket listed out. It's idempotent: run it again and it just regenerates the same day's file, so if the machine was asleep at 22:00 I can regenerate the current day by hand (or my agent does it at the start of a session). No state, no database — the digest is a pure function of `todo.txt`\n\n.\n\nThe rollup also appends an ASCII Gantt chart. A separate `gantt`\n\ncommand renders the board's `start:`\n\n→`due:`\n\nranges two ways: ASCII in the terminal, and a **Mermaid** diagram written to `gantt.md`\n\nthat renders on GitHub, in Obsidian, or on mermaid.live. The Gantt is a *view*, never a second copy of the data — tasks without a `due:`\n\nsimply don't appear.\n\nFor \"leave it open and add/complete on the spot,\" there's a full-screen curses TUI (`todo-tui.py`\n\n). It imports nothing but the Python standard library — `curses`\n\n, `os`\n\n, `re`\n\n, `sys`\n\n, `unicodedata`\n\n, `datetime`\n\n. No pip install, ever.\n\nIt shows `todo.txt`\n\nlive and, crucially, watches the file's mtime: if `todo.sh`\n\n, cron, an agent, or a phone app rewrites the file, the TUI reloads automatically. `a`\n\nadds, `d`\n\n/`Enter`\n\ncompletes, `e`\n\nedits a line in place, `/`\n\nfilters, and `Tab`\n\ncycles between the list, the Gantt view, and an issues view. I keep it pinned in a dedicated `tmux`\n\npane.\n\nBecause it's the same `todo.txt`\n\nunderneath, nothing about the TUI is privileged. It's just one more editor of the file.\n\nHere's the part that made this click for a human-plus-AI setup.\n\nAn AI coding agent already has three verbs that work perfectly on a text file: **Read**, **Edit**, and **Grep**. A `todo.txt`\n\nneeds no adapter, no MCP server, no OAuth dance, no rate limit. The agent opens the file the same way it opens any source file in the repo, and it understands the format after seeing it once because the format is *self-evident* — it's just lines.\n\nCompare that to a SaaS board. To let an agent touch a hosted kanban you need an integration, credentials, and a network round-trip — and interactive-auth integrations are exactly the thing that tends to be *missing* in headless contexts: a cron job, a scheduled agent, a CI run. A plain file in the repo is always reachable, from every one of those contexts, with zero setup.\n\nPlain text buys you three more things for free:\n\n`git log`\n\non one file.`+myapp`\n\n?\" is `grep +myapp todo.txt`\n\n, for me and for the agent identically.The format being boring is the feature. There's no layer where the human's mental model and the agent's mental model can drift apart, because there's no layer at all — just the file.\n\nThe day-to-day loop is the payoff. In the middle of a coding session I say something like *\"add a task to ship the CSV export by Friday,\"* and the agent runs:\n\n```\ntodo.sh add \"(A) ship CSV export +myapp @dev due:fri\"\n```\n\nThe relative `due:fri`\n\nbecomes a concrete date, the line lands in `todo.txt`\n\n, and the TUI in my other pane redraws a second later because its mtime watch fired. When the work is done, *\"mark the CSV export done\"* becomes `todo.sh done \"CSV export\"`\n\nand the line moves to the archive. Nothing I say has to be structured; the agent knows the schema and fills it in.\n\nThere's no lock and no coordination protocol, and yet the human, the CLI, the cron job, and the TUI never fight, because there's exactly one writer pattern — append a line, or filter-and-rewrite — over one small file, and the TUI treats the file as the truth rather than caching its own copy. \"Just say it and it's on the board\" isn't a feature anyone built; it falls out of everyone sharing the same plain-text file.\n\nWhen your collaborators are AI agents, the interface you share with them matters more than the features of any one tool. A hosted board optimizes for a human clicking a UI. A `todo.txt`\n\noptimizes for *anything that can read a file* — you, your shell, a cron line, a phone app, and an LLM agent — participating on equal footing with no integration in between.\n\nPick the substrate your agents can already touch. For a task list, that substrate is a plain-text file, and the whole rest of the system is a few dozen lines of dependency-free glue.\n\n*This is part of a series on human-AI collaboration patterns. Two companion pieces — one on the collaboration \"shape\" I use with coding agents, and one on a \"don't decide too early / keep options live\" discipline — are still in the drafts and will link here once published.*\n\nThe board conventions and the CLI/TUI behavior described here are taken from the actual tooling (a `README.md`\n\nspec, a small bash CLI, and a dependency-free curses TUI). All task examples in this post are fictional; the real board's contents are omitted.\n\n── I run a suite of self-hosted business tools in production. I take on consulting for legacy modernization and shared-hosting constraints. Contact: github.com/hideyukiMORI", "url": "https://wpnews.pro/news/a-todo-txt-shared-by-a-human-and-ai-agents-why-plain-text-beat-a-saas-board-for", "canonical_source": "https://dev.to/hideyukimori/a-todotxt-shared-by-a-human-and-ai-agents-why-plain-text-beat-a-saas-board-for-my-workflow-5dbh", "published_at": "2026-07-17 19:14:11+00:00", "updated_at": "2026-07-17 19:30:57.354677+00:00", "lang": "en", "topics": ["developer-tools", "ai-agents", "artificial-intelligence"], "entities": ["todo.txt", "Mermaid", "GitHub", "Obsidian"], "alternates": {"html": "https://wpnews.pro/news/a-todo-txt-shared-by-a-human-and-ai-agents-why-plain-text-beat-a-saas-board-for", "markdown": "https://wpnews.pro/news/a-todo-txt-shared-by-a-human-and-ai-agents-why-plain-text-beat-a-saas-board-for.md", "text": "https://wpnews.pro/news/a-todo-txt-shared-by-a-human-and-ai-agents-why-plain-text-beat-a-saas-board-for.txt", "jsonld": "https://wpnews.pro/news/a-todo-txt-shared-by-a-human-and-ai-agents-why-plain-text-beat-a-saas-board-for.jsonld"}}