Message your Telegram bot in plain words and it becomes a Todoist task, due when you said - using only the words you typed.
Uses
Claude
TelegramTodoist
Text a task to Todoist
Whenever you message your Telegram bot in plain words, the message becomes a Todoist task in the project you name, due when you said.
The AI reads the message only to split it into the task and the timing words, and what it hands back is checked against your original message before anything is created. The task text must appear in what you sent, and so must the due phrase; anything that has drifted is thrown away, so a task can only ever contain words you typed and never gets a deadline you did not mention. A message with no timing becomes a task with no due date. If the named project does not exist the run stops and tells you which projects the account does have. Every task is confirmed back in the chat, with the due date it was given.
Before the first run you need a Telegram bot in a chat you use only for capture, since every message becomes a task, and a Todoist project to file into.
incomingMessage.When a new message is received. Save it as incomingMessage.projectName to blank.Set projectName to blank.messageText to blank.Set messageText to blank.noTextErrorIf a step below fails, save the error as noTextErrorincomingMessage.text and save it as messageText.Trim incomingMessage.text and save it as messageText.messageText is emptyIf messageText is emptytodoistProjects.List projects. Save it as todoistProjects.projectName lowercase and save it as wantedProject.Make projectName lowercase and save it as wantedProject.projectId to blank.Set projectId to blank.knownProjectNames to an empty list.Set knownProjectNames to an empty list.project in todoistProjects:For each project in todoistProjects:candidateName to blank.Set candidateName to blank.projectNameErrorIf a step below fails, save the error as projectNameErrorproject.name and save it as candidateName.Trim project.name and save it as candidateName.candidateName isn't emptyIf candidateName isn't emptycandidateName to the end of knownProjectNames and save it as knownProjectNames.Add candidateName to the end of knownProjectNames and save it as knownProjectNames.candidateName in lowercase is wantedProject and projectId is emptyIf candidateName in lowercase is wantedProject and projectId is emptyprojectIdErrorIf a step below fails, save the error as projectIdErrorproject.id and save it as projectId.Trim project.id and save it as projectId.projectId is emptyIf projectId is emptyknownProjectNames with , and save it as knownProjects.Join knownProjectNames with , and save it as knownProjects.knownProjects. Correct the 'projectName' step to match one of them.Stop and report a problem: No Todoist project is named '@projectName'. The projects on this account are: knownProjects. Correct the 'projectName' step to match one of them.splitPrompt to You are splitting one short message into a task and, if the message says when, a due date.Set splitPrompt to You are splitting one short message into a task and, if the message says when, a due date.
Reply with exactly two lines and nothing else:
TASK: <what to do>
WHEN: <when it is due, or the single word none>
Copy both lines word for word out of the message. Do not invent, rephrase, translate, correct or add anything the message does not already say.
TASK must be one unbroken run of words taken from the message. If the timing words sit in the middle of the sentence and taking them out would break it up, copy the whole message into TASK and still report the timing words in WHEN.
If the message says nothing about when, write WHEN: none.
Message:
messageText.modelReply to blank.Set modelReply to blank.modelErrorIf a step below fails, save the error as modelErrorsplitPrompt. Save it as splitResult.Ask Claude: splitPrompt. Save it as splitResult.
Maximum response length: 200splitResult.response_text and save it as modelReply.Trim splitResult.response_text and save it as modelReply.taskText to messageText.Set taskText to messageText.duePhrase to blank.Set duePhrase to blank.modelReply isn't emptyIf modelReply isn't emptymodelReply split by TASK: and save it as afterTaskMarker.Get the last item of modelReply split by TASK: and save it as afterTaskMarker.afterTaskMarker split by WHEN: and save it as proposedTask.Trim the first item of afterTaskMarker split by WHEN: and save it as proposedTask.proposedTask isn't empty and messageText contains proposedTask (ignoring…If proposedTask isn't empty and messageText contains proposedTask (ignoring…taskText to proposedTask.Change taskText to proposedTask.modelReply split by WHEN: and save it as proposedWhen.Trim the last item of modelReply split by WHEN: and save it as proposedWhen.proposedWhen isn't empty and proposedWhen in lowercase is not none and…If proposedWhen isn't empty and proposedWhen in lowercase is not none and…duePhrase to proposedWhen.Change duePhrase to proposedWhen.taskText.Create task taskText.
Project ID: projectId
Due date: duePhraseconfirmation to Added to projectName: taskText.Set confirmation to Added to projectName: taskText.duePhrase isn't emptyIf duePhrase isn't emptyconfirmation to confirmation (due duePhrase).Change confirmation to confirmation (due duePhrase).incomingMessage.chat_id.Send a message to chat incomingMessage.chat_id.confirmation