Skip to content
Every GTD app I’ve tried falls into one of two camps: either it’s a complex beast with more features than I’ll ever use (looking at you, OmniFocus), or it’s simple but forces me to manually categorize everything with rigid syntax.
What I wanted was simple: type “buy milk tomorrow” into my phone and have it land in the right place. No app switching, no form fields, no learning curve.
The Gap in the Market
I surveyed the landscape. Todoist has excellent natural language parsing - you can type “Call dentist next Tuesday at 2pm #errands” and it just works. But Todoist is bloated for my needs. I don’t want Kanban boards, team collaboration, or productivity gamification. I want a scratchpad that understands English.
What about Telegram bots? Telegram is already on my phone, always running, and has an excellent bot API. Surely someone has built a GTD bot?
I couldn’t find one. There are todo list bots, reminder bots, and note-taking bots. But nothing that implements actual GTD methodology - the inbox/next/scheduled/someday workflow that David Allen describes - with natural language understanding.
So I built one.
The Solution: 839 Lines of Python
Jarvis Lite is a single-file Python bot that implements GTD principles with Claude Haiku handling all the natural language parsing. The entire thing took under an hour to build using Claude Code.
The stack:
- python-telegram-bot for the Telegram integration
- PostgreSQL for persistent storage
- Claude Haiku for parsing natural language into structured actions
- APScheduler for the daily morning digest
One-click deployment to Render with a managed Postgres database.
How It Works
Natural Language Parsing with Claude Haiku
The core insight is that you don’t need complex NLP libraries or custom models. Claude Haiku is fast, cheap, and remarkably good at intent classification. Every message the user sends gets parsed through this system prompt:
Code
system_prompt = f"""You are a GTD task parser. Parse the user's message into a JSON action.
Today's date is {today_date}.
Actions:
- add: Add a new task. Extract the task text (keep @tags in the text) and determine the list.
- complete: Mark a task as done. Look for "done", "finished", "complete", etc.
- delete: Remove a task. Look for "delete", "remove", etc.
- move: Move a task to a different list. Look for "move X to Y", "X to next", "X scheduled tomorrow".
- show: Display tasks. Look for "show", "list", "what's next", etc. Can filter by @tag.
- review: Weekly review. Look for "review", "weekly review", etc.
- today: Mark a task for today's focus. Look for "today X", "focus X", "star X".
- clear_today: Clear all today markers.
- process: Start inbox processing. Look for "process", "process inbox", "triage".
- help: User needs help.
Lists:
- inbox: Default for new tasks without a specific list
- next: Tasks to do within 7 days. Look for "#next", "next:", or context implying urgency
- scheduled: Tasks with a due date. Parse dates like "tomorrow", "next monday", "Dec 15", etc.
- someday: Future/maybe tasks. Look for "someday", "maybe", "later", etc.
Context tags (@work, @home, @errands, etc.) should be kept in the task text as-is.
Respond with ONLY valid JSON, no other text:
{{
"action": "add|complete|delete|move|show|review|today|clear_today|process|help|unknown",
"text": "task text if adding (include @tags)",
"list": "inbox|next|scheduled|someday|today|null",
"task_id": null or number,
"due_date": null or "YYYY-MM-DD",
"text_match": "partial text to match for completion",
"tag": "tag name without @ for filtering"
}}"""
The examples section (omitted for brevity) shows Haiku how to handle inputs like:
- “Buy milk” →
{"action": "add", "text": "Buy milk", "list": "inbox"}
- “Call bank tomorrow” →
{"action": "add", "text": "Call bank", "list": "scheduled", "due_date": "2025-12-21"}
- “#next: finish report @work” →
{"action": "add", "text": "finish report @work", "list": "next"}
- “Done: buy milk” →
{"action": "complete", "text_match": "buy milk"}
- “3 to next” →
{"action": "move", "task_id": 3, "list": "next"}
Haiku returns structured JSON that the bot then acts on. If parsing fails or the action is unknown, the message gets added to inbox as a fallback - you never lose a thought.
The GTD Data Model
The database schema is minimal:
Code
CREATE TABLE tasks (
id SERIAL PRIMARY KEY,
user_id BIGINT NOT NULL,
text TEXT NOT NULL,
list VARCHAR(20) NOT NULL DEFAULT 'inbox',
due_date DATE,
is_today BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
completed_at TIMESTAMP
)
Four lists matching GTD methodology:
- inbox: Capture everything, process later
- next: Actionable tasks for this week
- scheduled: Tasks with specific due dates
- someday: Maybe/future items
The is_today flag lets you pick 3-5 tasks for daily focus - a key GTD concept that most apps ignore. Context tags like @work or @errands are stored in the task text itself and searchable via “show @work”.
Morning Digest
APScheduler sends a daily summary at 7am with:
- Your today’s focus tasks
- Overdue items
- Tasks due today
- Suggested next actions
This replaces the need to open an app and review - the bot comes to you.
Building with Claude Code
The entire bot - from zero to deployed - took under an hour with Claude Code. Here’s what that looked like:
- I described what I wanted: a GTD Telegram bot with natural language parsing
- Claude Code generated the initial bot.py with the Haiku integration
- We iterated on the prompt engineering to improve parsing accuracy
- Claude Code added the database layer, then deployment configs for Render
- I deployed, tested with real messages, and refined
The Claude Code workflow shines for this kind of project. You’re not fighting boilerplate or looking up API docs. You describe intent and iterate on the result. The prompt engineering phase - refining how Haiku interprets messages - was the bulk of the work, and having Claude Code suggest prompt improvements was genuinely useful.
Try It
The bot is live at @gtdlitebot - though it’s currently single-user (me). The code is on GitHub if you want to deploy your own instance.
What’s Missing
This is a v0.1. Some obvious improvements:
Recurring tasks: “Water plants every Sunday” doesn’t work yet. Would need to add a recurrence pattern to the schema and logic to regenerate tasks.
Projects and areas: Real GTD has hierarchical projects. Currently everything is flat. You can fake it with tags, but it’s not the same.
Voice input: Telegram supports voice messages. Whisper transcription could make capture even more frictionless.
Time-based reminders: Push notifications at specific times, not just the morning digest.
Calendar sync: Export scheduled tasks to Google Calendar.
Analytics: What days am I most productive? What contexts get neglected? The data is there, the dashboard isn’t.
But for now, it does what I need: captures thoughts in natural language and organizes them according to GTD principles. Built in an hour. That’s the power of LLMs as parsing layers - you can build surprisingly capable tools with very little code.