task_batch_update
Update multiple tasks at once by specifying IDs to change their status, priority, or assignee.
Instructions
Update multiple tasks at once. Useful for changing status of several tasks (e.g., mark 3 tasks as done) or reassigning tasks.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| ids | Yes | Task IDs to update | |
| status | No | ||
| priority | No | ||
| assigned_to | No |
Implementation Reference
- src/tools/activity.ts:150-239 (handler)The main handler function for task_batch_update. Iterates over task IDs, updates status/priority/assigned_to in a transaction, logs changes, auto-tracks time when moving to 'done', and re-evaluates downstream dependencies.
function handleTaskBatchUpdate(args: Record<string, unknown>) { const db = getDb(); const ids = args.ids as number[]; const status = args.status as string | undefined; const priority = args.priority as string | undefined; const assignedTo = args.assigned_to as string | undefined; if (!status && !priority && assignedTo === undefined) { throw new Error('Provide at least one field to update: status, priority, or assigned_to'); } const getStmt = db.prepare('SELECT * FROM tasks WHERE id = ?'); const results = db.transaction(() => { return ids.map((id) => { const oldRow = getStmt.get(id) as Record<string, unknown> | undefined; if (!oldRow) throw new Error(`Task ${id} not found`); const updates: string[] = []; const params: unknown[] = []; if (status) { updates.push('status = ?'); params.push(status); } if (priority) { updates.push('priority = ?'); params.push(priority); } if (assignedTo !== undefined) { updates.push('assigned_to = ?'); params.push(assignedTo); } updates.push("updated_at = datetime('now')"); params.push(id); const newRow = db .prepare(`UPDATE tasks SET ${updates.join(', ')} WHERE id = ? RETURNING *`) .get(...params) as Record<string, unknown>; // Log status changes if (status && oldRow.status !== status) { logActivity( db, 'task', id, 'status_changed', 'status', oldRow.status as string, status, `Task '${newRow.title}' status: ${oldRow.status} -> ${status}` ); } if (priority && oldRow.priority !== priority) { logActivity( db, 'task', id, 'updated', 'priority', oldRow.priority as string, priority, `Task '${newRow.title}' priority: ${oldRow.priority} -> ${priority}` ); } // Auto time tracking if (status === 'done' && oldRow.status !== 'done' && !newRow.actual_hours) { const startEntry = db.prepare( `SELECT created_at FROM activity_log WHERE entity_type = 'task' AND entity_id = ? AND action = 'status_changed' AND field_name = 'status' AND new_value = 'in_progress' ORDER BY created_at DESC LIMIT 1` ).get(id) as { created_at: string } | undefined; if (startEntry) { const startMs = new Date(startEntry.created_at + 'Z').getTime(); const nowMs = Date.now(); const hours = Math.round(((nowMs - startMs) / 3_600_000) * 10) / 10; if (hours > 0) { db.prepare('UPDATE tasks SET actual_hours = ? WHERE id = ?').run(hours, id); newRow.actual_hours = hours; logActivity(db, 'task', id, 'updated', 'actual_hours', null, String(hours), `Task '${newRow.title}' auto-tracked: ${hours}h`); } } } // Re-evaluate downstream dependencies when task marked done if (status === 'done' && oldRow.status !== 'done') { reevaluateDownstream(db, id); } return newRow; }); })(); return { updated: results.length, tasks: results }; } - src/tools/activity.ts:48-67 (schema)Input schema definition for task_batch_update. Accepts 'ids' (required array of integers), plus optional 'status', 'priority', and 'assigned_to'.
{ name: 'task_batch_update', description: 'Update multiple tasks at once. Useful for changing status of several tasks (e.g., mark 3 tasks as done) or reassigning tasks.', annotations: { title: 'Batch Update Tasks', readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false }, inputSchema: { type: 'object', properties: { ids: { type: 'array', items: { type: 'integer' }, description: 'Task IDs to update', }, status: { type: 'string', enum: ['todo', 'in_progress', 'review', 'done', 'blocked'] }, priority: { type: 'string', enum: ['low', 'medium', 'high', 'critical'] }, assigned_to: { type: 'string' }, }, required: ['ids'], }, }, - src/tools/activity.ts:241-245 (registration)Registration of task_batch_update handler in the exported handlers map used by src/index.ts.
export const handlers: Record<string, ToolHandler> = { activity_log: handleActivityLog, tracker_session_diff: handleSessionDiff, task_batch_update: handleTaskBatchUpdate, }; - src/index.ts:23-35 (registration)Top-level tool registration: activityDefs (which includes task_batch_update schema) is spread into ALL_TOOLS array.
const ALL_TOOLS: Tool[] = [ ...projectDefs, ...epicDefs, ...taskDefs, ...subtaskDefs, ...noteDefs, ...commentDefs, ...templateDefs, ...dashboardDefs, ...searchDefs, ...activityDefs, ...exportImportDefs, ]; - src/tools/tasks.ts:167-175 (helper)reevaluateDownstream helper - called by handleTaskBatchUpdate when tasks are marked 'done' to re-evaluate dependencies of downstream tasks.
export function reevaluateDownstream(db: Database.Database, completedTaskId: number): void { const downstream = db.prepare( 'SELECT task_id FROM task_dependencies WHERE depends_on_task_id = ?' ).all(completedTaskId) as Array<{ task_id: number }>; for (const row of downstream) { evaluateAndUpdateDependencies(db, row.task_id); } }