update_tasks
Modify existing Todoist tasks by updating their content, due dates, priorities, labels, or other attributes using either task ID or name for identification.
Instructions
Update tasks in Todoist Either 'task_id' or the 'task_name' to identify the target.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| items | Yes |
Implementation Reference
- src/utils/handlers.ts:201-353 (handler)Core batch API handler logic for 'update_tasks': processes batch of items supporting task_id or task_name lookup, validates path params, performs POST /tasks/{id} via todoistApi with update fields, returns per-item results and summary.const handler = async (args: z.infer<typeof batchSchema>): Promise<any> => { const { items } = args; // For modes other than create, check if name lookup is needed let allItems: any[] = []; const needsNameLookup = options.mode !== 'create' && options.nameField && options.findByName && items.some(item => item[options.nameField!] && !item[options.idField!]); if (needsNameLookup) { // Determine the base path for fetching all items // Example: /tasks from /tasks/{id} const lookupPath = options.basePath || (options.path ? options.path.split('/{')[0] : ''); allItems = await todoistApi.get(lookupPath, {}); } const results = await Promise.all( items.map(async item => { if (options.validateItem) { const validation = options.validateItem(item); if (!validation.valid) { return { success: false, error: validation.error || 'Validation failed', item, }; } } try { let finalPath = ''; const apiParams = { ...item }; // For modes where need id if (options.mode !== 'create' && options.idField) { let itemId = item[options.idField]; let matchedName = null; let matchedContent = null; // If no ID but name is provided, search by name if (!itemId && item[options.nameField!] && options.findByName) { const searchName = item[options.nameField!]; const matchedItem = options.findByName(searchName, allItems); if (!matchedItem) { return { success: false, error: `Item not found with name: ${searchName}`, item, }; } itemId = matchedItem.id; matchedName = searchName; matchedContent = matchedItem.content; } if (!itemId) { return { success: false, error: `Either ${options.idField} or ${options.nameField} must be provided`, item, }; } // Apply security validation to itemId before using in path const safeItemId = validatePathParameter(itemId, options.idField || 'id'); if (options.basePath && options.pathSuffix) { finalPath = `${options.basePath}${options.pathSuffix.replace('{id}', safeItemId)}`; } else if (options.path) { finalPath = options.path.replace('{id}', safeItemId); } delete apiParams[options.idField]; if (options.nameField) { delete apiParams[options.nameField]; } let result; switch (options.method) { case 'GET': result = await todoistApi.get(finalPath, apiParams); break; case 'POST': result = await todoistApi.post(finalPath, apiParams); break; case 'DELETE': result = await todoistApi.delete(finalPath); break; } const response: any = { success: true, id: itemId, result, }; if (matchedName) { response.found_by_name = matchedName; response.matched_content = matchedContent; } return response; } // Create mode else { finalPath = options.path || options.basePath || ''; let result; switch (options.method) { case 'GET': result = await todoistApi.get(finalPath, apiParams); break; case 'POST': result = await todoistApi.post(finalPath, apiParams); break; case 'DELETE': result = await todoistApi.delete(finalPath); break; } return { success: true, created_item: result, }; } } catch (error) { return { success: false, error: error instanceof Error ? error.message : String(error), item, }; } }) ); const successCount = results.filter(r => r.success).length; return { success: successCount === items.length, summary: { total: items.length, succeeded: successCount, failed: items.length - successCount, }, results, }; };
- src/tools/tasks.ts:121-136 (registration)Registers the 'update_tasks' tool via createBatchApiHandler: sets name, description, itemSchema (task_id/name + create_fields), method POST, path '/tasks/{id}', mode 'update', findByName helper.createBatchApiHandler({ name: 'update_tasks', description: 'Update tasks in Todoist', itemSchema: { task_id: z.string().optional(), task_name: z.string().optional(), ...create_fields, }, method: 'POST', path: '/tasks/{id}', mode: 'update', idField: 'task_id', nameField: 'task_name', findByName: (name, items) => items.find(item => item.content.toLowerCase().includes(name.toLowerCase())), });
- src/tools/tasks.ts:10-63 (schema)Common Zod schema (create_fields) for task updates: content, description, labels, priority, due_string/date/datetime/lang, assignee_id, duration/unit, deadline_*./// Common fields for create and update tasks const create_fields = { content: z .string() .describe('Task title (brief). May contain markdown-formatted text and hyperlinks'), description: z .string() .optional() .describe('Description (detailed). May contain markdown-formatted text and hyperlinks'), labels: z.array(z.string()).optional(), priority: z.number().int().min(1).max(4).optional().describe('From 1 (urgent) to 4 (normal)'), due_string: z .string() .optional() .describe( 'Human defined task due date (ex.: "next Monday", "Tomorrow"). Value is set using local (not UTC) time, if not in english provided, due_lang should be set to the language of the string' ), due_date: z .string() .optional() .describe( 'Due date in YYYY-MM-DD format relative to user timezone (when you plan to work on task)' ), due_datetime: z.string().optional().describe('Specific date and time in RFC3339 format in UTC'), due_lang: z .string() .optional() .describe('2-letter code specifying language in case due_string is not written in english'), assignee_id: z .string() .optional() .describe('The responsible user ID (only applies to shared tasks)'), duration: z .number() .int() .positive() .optional() .describe( 'A positive (greater than zero) integer for the amount of duration_unit the task will take' ), duration_unit: z .enum(['minute', 'day']) .optional() .describe( 'The unit of time that the duration field represents. Must be either minute or day' ), deadline_date: z .string() .optional() .describe( 'Deadline date in YYYY-MM-DD format relative to user timezone (fixed date when task must be completed, for tasks with external consequences)' ), deadline_lang: z.string().optional().describe('2-letter code specifying language of deadline'), };
- src/tools/tasks.ts:123-128 (schema)Specific itemSchema for update_tasks: task_id (opt), task_name (opt), spreads create_fields.description: 'Update tasks in Todoist', itemSchema: { task_id: z.string().optional(), task_name: z.string().optional(), ...create_fields, },
- src/tools/tasks.ts:134-135 (helper)findByName helper: finds task by partial content match (case-insensitive).findByName: (name, items) => items.find(item => item.content.toLowerCase().includes(name.toLowerCase())),