Skip to main content
Glama

update_task

Modify task details, dependencies, priorities, and statuses to maintain accurate and up-to-date project workflows. Supports hierarchy adjustments, time tracking, and advanced project management.

Instructions

Adapt and refine tasks with comprehensive updates including dependencies, priorities, complexity, status, tags, and time tracking. Keep your workflow current and accurate with advanced project management capabilities including unlimited hierarchy movement.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
actualHoursNoActual time spent on the task in hours
completedNoMark task as completed (true) or incomplete (false) (optional)
complexityNoUpdated complexity/effort estimate (1-10, where 10 is most complex)
dependsOnNoUpdated array of task IDs that must be completed before this task
detailsNoNew detailed description for the task (optional)
estimatedHoursNoUpdated estimated time to complete in hours
idYesThe unique identifier of the task to update
nameNoNew name/title for the task (optional)
parentIdNoUpdated parent task ID for moving between hierarchy levels (optional - use null/empty to move to top level)
priorityNoUpdated task priority level (1-10, where 10 is highest priority)
statusNoUpdated task status
tagsNoUpdated tags for categorization and filtering
workingDirectoryYesThe full absolute path to the working directory where data is stored. MUST be an absolute path, never relative. Windows: "C:\Users\username\project" or "D:\projects\my-app". Unix/Linux/macOS: "/home/username/project" or "/Users/username/project". Do NOT use: ".", "..", "~", "./folder", "../folder" or any relative paths. Ensure the path exists and is accessible before calling this tool. NOTE: When server is started with --claude flag, this parameter is ignored and a global user directory is used instead.

Implementation Reference

  • Main handler for 'update_task' tool. Validates inputs, checks for hierarchy cycles and constraints, calls storage.updateTask, formats success/error responses with hierarchy info.
    export function createUpdateTaskTool(storage: Storage) {
      return {
        name: 'update_task',
        description: 'Update task properties including name, details, parent relationship (parentId), completion status, dependencies, priority, complexity, status, tags, and time estimates. Use parentId to move tasks within the hierarchy.',
        inputSchema: {
          id: z.string(),
          name: z.string().optional(),
          details: z.string().optional(),
          parentId: z.string().optional(),
          completed: z.boolean().optional(),
          dependsOn: z.array(z.string()).optional(),
          priority: z.number().min(1).max(10).optional(),
          complexity: z.number().min(1).max(10).optional(),
          status: z.enum(['pending', 'in-progress', 'blocked', 'done']).optional(),
          tags: z.array(z.string()).optional(),
          estimatedHours: z.number().min(0).optional(),
          actualHours: z.number().min(0).optional()
        },
        handler: async ({ id, name, details, parentId, completed, dependsOn, priority, complexity, status, tags, estimatedHours, actualHours }: {
          id: string;
          name?: string;
          details?: string;
          parentId?: string;
          completed?: boolean;
          dependsOn?: string[];
          priority?: number;
          complexity?: number;
          status?: 'pending' | 'in-progress' | 'blocked' | 'done';
          tags?: string[];
          estimatedHours?: number;
          actualHours?: number;
        }) => {
          try {
            // Validate inputs
            if (!id || id.trim().length === 0) {
              return {
                content: [{
                  type: 'text' as const,
                  text: 'Error: Task ID is required.'
                }],
                isError: true
              };
            }
    
            if (name !== undefined && (!name || name.trim().length === 0)) {
              return {
                content: [{
                  type: 'text' as const,
                  text: 'Error: Task name must not be empty.'
                }],
                isError: true
              };
            }
    
            if (name !== undefined && name.trim().length > 100) {
              return {
                content: [{
                  type: 'text' as const,
                  text: 'Error: Task name must be 100 characters or less.'
                }],
                isError: true
              };
            }
    
            if (details !== undefined && (!details || details.trim().length === 0)) {
              return {
                content: [{
                  type: 'text' as const,
                  text: 'Error: Task details must not be empty.'
                }],
                isError: true
              };
            }
    
            if (details !== undefined && details.trim().length > 2000) {
              return {
                content: [{
                  type: 'text' as const,
                  text: 'Error: Task details must be 2000 characters or less.'
                }],
                isError: true
              };
            }
    
            if (name === undefined && details === undefined && parentId === undefined && completed === undefined &&
                dependsOn === undefined && priority === undefined && complexity === undefined &&
                status === undefined && tags === undefined && estimatedHours === undefined &&
                actualHours === undefined) {
              return {
                content: [{
                  type: 'text' as const,
                  text: 'Error: At least one field must be provided for update.'
                }],
                isError: true
              };
            }
    
            const existingTask = await storage.getTask(id.trim());
    
            if (!existingTask) {
              return {
                content: [{
                  type: 'text' as const,
                  text: `Error: Task with ID "${id}" not found. Use list_tasks to see all available tasks.`
                }],
                isError: true
              };
            }
    
            // Validate parentId if provided
            let newParentTask = null;
            if (parentId !== undefined) {
              if (parentId) {
                if (parentId === id) {
                  return {
                    content: [{
                      type: 'text' as const,
                      text: `Error: Task cannot be its own parent.`
                    }],
                    isError: true
                  };
                }
    
                newParentTask = await storage.getTask(parentId.trim());
                if (!newParentTask) {
                  return {
                    content: [{
                      type: 'text' as const,
                      text: `Error: Parent task with ID "${parentId}" not found.`
                    }],
                    isError: true
                  };
                }
    
                // Ensure parent is in the same project
                if (newParentTask.projectId !== existingTask.projectId) {
                  return {
                    content: [{
                      type: 'text' as const,
                      text: `Error: Parent task must be in the same project.`
                    }],
                    isError: true
                  };
                }
    
                // Check for circular dependencies (would the new parent be a descendant?)
                const children = await storage.getTaskChildren(id);
                const allDescendants = await getAllDescendants(storage, id);
                if (allDescendants.includes(parentId)) {
                  return {
                    content: [{
                      type: 'text' as const,
                      text: `Error: Cannot move task under its own descendant. This would create a circular hierarchy.`
                    }],
                    isError: true
                  };
                }
              }
            }
    
            // Check for name uniqueness within the same parent scope if name is being updated
            if (name && name.toLowerCase() !== existingTask.name.toLowerCase()) {
              const effectiveParentId = parentId !== undefined ? parentId : existingTask.parentId;
              const siblingTasks = await storage.getTasks(existingTask.projectId, effectiveParentId);
              const nameExists = siblingTasks.some(t => t.id !== id && t.name.toLowerCase() === name.toLowerCase());
    
              if (nameExists) {
                const scopeDescription = newParentTask
                  ? `under parent task "${newParentTask.name}"`
                  : effectiveParentId
                    ? 'in the current parent scope'
                    : 'at the top level of this project';
                return {
                  content: [{
                    type: 'text' as const,
                    text: `Error: A task with the name "${name}" already exists ${scopeDescription}. Please choose a different name.`
                  }],
                  isError: true
                };
              }
            }
    
            // Validate dependencies exist if provided
            if (dependsOn && dependsOn.length > 0) {
              for (const depId of dependsOn) {
                if (depId === id) {
                  return {
                    content: [{
                      type: 'text' as const,
                      text: `Error: Task cannot depend on itself.`
                    }],
                    isError: true
                  };
                }
                const depTask = await storage.getTask(depId);
                if (!depTask) {
                  return {
                    content: [{
                      type: 'text' as const,
                      text: `Error: Dependency task with ID "${depId}" not found.`
                    }],
                    isError: true
                  };
                }
              }
            }
    
            const updates: any = {
              updatedAt: new Date().toISOString()
            };
    
            if (name !== undefined) {
              updates.name = name.trim();
            }
    
            if (details !== undefined) {
              updates.details = details.trim();
            }
    
            if (parentId !== undefined) {
              updates.parentId = parentId?.trim() || undefined;
            }
    
            if (completed !== undefined) {
              updates.completed = completed;
            }
    
            if (dependsOn !== undefined) {
              updates.dependsOn = dependsOn;
            }
    
            if (priority !== undefined) {
              updates.priority = priority;
            }
    
            if (complexity !== undefined) {
              updates.complexity = complexity;
            }
    
            if (status !== undefined) {
              updates.status = status;
            }
    
            if (tags !== undefined) {
              updates.tags = tags;
            }
    
            if (estimatedHours !== undefined) {
              updates.estimatedHours = estimatedHours;
            }
    
            if (actualHours !== undefined) {
              updates.actualHours = actualHours;
            }
    
            const updatedTask = await storage.updateTask(id, updates);
    
            if (!updatedTask) {
              return {
                content: [{
                  type: 'text' as const,
                  text: `Error: Failed to update task with ID "${id}".`
                }],
                isError: true
              };
            }
    
            // Get project and hierarchy information for display
            const project = await storage.getProject(updatedTask.projectId);
            const projectName = project ? project.name : 'Unknown Project';
            const currentParent = updatedTask.parentId ? await storage.getTask(updatedTask.parentId) : null;
            const taskLevel = updatedTask.level || 0;
    
            const changedFields = [];
            if (name !== undefined) changedFields.push('name');
            if (details !== undefined) changedFields.push('details');
            if (parentId !== undefined) changedFields.push('parent relationship');
            if (completed !== undefined) changedFields.push('completion status');
            if (dependsOn !== undefined) changedFields.push('dependencies');
            if (priority !== undefined) changedFields.push('priority');
            if (complexity !== undefined) changedFields.push('complexity');
            if (status !== undefined) changedFields.push('status');
            if (tags !== undefined) changedFields.push('tags');
            if (estimatedHours !== undefined) changedFields.push('estimated hours');
            if (actualHours !== undefined) changedFields.push('actual hours');
    
            const taskStatus = updatedTask.status || (updatedTask.completed ? 'done' : 'pending');
            const levelIndicator = '  '.repeat(taskLevel) + '→';
    
            // Build hierarchy path
            let hierarchyPath = projectName;
            if (currentParent) {
              const ancestors = await storage.getTaskAncestors(updatedTask.id);
              hierarchyPath = `${projectName} → ${ancestors.map(a => a.name).join(' → ')} → ${updatedTask.name}`;
            } else {
              hierarchyPath = `${projectName} → ${updatedTask.name}`;
            }
    
            return {
              content: [{
                type: 'text' as const,
                text: `✅ Task updated successfully!
    
    **${levelIndicator} ${updatedTask.name}** (ID: ${updatedTask.id})
    ${currentParent ? `Parent: ${currentParent.name} (${currentParent.id})` : 'Top-level task'}
    Project: ${projectName}
    Level: ${taskLevel} ${taskLevel === 0 ? '(Top-level)' : `(${taskLevel} level${taskLevel > 1 ? 's' : ''} deep)`}
    Path: ${hierarchyPath}
    
    📋 **Task Properties:**
    • Priority: ${updatedTask.priority || 'Not set'}/10
    • Complexity: ${updatedTask.complexity || 'Not set'}/10
    • Status: ${taskStatus}
    • Completed: ${updatedTask.completed ? 'Yes' : 'No'}
    • Tags: ${updatedTask.tags?.join(', ') || 'None'}
    • Dependencies: ${updatedTask.dependsOn?.length ? updatedTask.dependsOn.join(', ') : 'None'}
    • Estimated Hours: ${updatedTask.estimatedHours || 'Not set'}
    • Actual Hours: ${updatedTask.actualHours || 'Not set'}
    • Details: ${updatedTask.details}
    • Last Updated: ${new Date(updatedTask.updatedAt).toLocaleString()}
    
    ✏️ **Updated fields:** ${changedFields.join(', ')}
    
    🎯 **Next Steps:**
    ${parentId !== undefined ? '• Use `list_tasks` to see the updated hierarchy structure' : ''}
    • Use \`get_next_task_recommendation\` to see what to work on next
    • Run \`analyze_task_complexity\` if complexity has changed
    ${taskLevel > 0 ? '• Consider breaking down further with create_task using this task as parentId' : ''}`
              }]
            };
          } catch (error) {
            return {
              content: [{
                type: 'text' as const,
                text: `Error updating task: ${error instanceof Error ? error.message : 'Unknown error'}`
              }],
              isError: true
            };
          }
        }
      };
    }
  • TypeScript interface defining the UpdateTaskInput shape, matching the tool's inputSchema for validation.
    export interface UpdateTaskInput {
      /** Task name (optional) */
      name?: string;
      /** Enhanced task description (optional) */
      details?: string;
      /** Reference to parent task (optional) */
      parentId?: string;
      /** Task completion status (optional) */
      completed?: boolean;
      /** Task dependencies - IDs of tasks that must be completed before this task */
      dependsOn?: string[];
      /** Task priority level (1-10, where 10 is highest priority) */
      priority?: number;
      /** Estimated complexity/effort (1-10, where 10 is most complex) */
      complexity?: number;
      /** Task status */
      status?: 'pending' | 'in-progress' | 'blocked' | 'done';
      /** Tags for categorization and filtering */
      tags?: string[];
      /** Estimated time to complete in hours */
      estimatedHours?: number;
      /** Actual time spent in hours */
      actualHours?: number;
    }
  • Registers the 'update_task' tool by including createUpdateTaskTool(storage) in the createTaskTools export.
    export function createTaskTools(storage: Storage) {
      return {
        create_task: createCreateTaskTool(storage),
        delete_task: createDeleteTaskTool(storage),
        get_task: createGetTaskTool(storage),
        list_tasks: createListTasksTool(storage),
        update_task: createUpdateTaskTool(storage),
        migrate_subtasks: createMigrateSubtasksTool(storage),
        move_task: createMoveTaskTool(storage)
      };
    }
  • Core storage method updateTask called by the tool handler to persist task updates to JSON file, including hierarchy validation.
    async updateTask(id: string, updates: Partial<Task>): Promise<Task | null> {
      const index = this.data.tasks.findIndex(t => t.id === id);
      if (index === -1) return null;
    
      const task = this.data.tasks[index];
    
      // If updating parentId, validate the new parent
      if (updates.parentId !== undefined) {
        if (updates.parentId) {
          const parent = await this.getTask(updates.parentId);
          if (!parent) {
            throw new Error(`Parent task with id ${updates.parentId} not found`);
          }
          // Prevent circular references
          if (await this.wouldCreateCircularReference(id, updates.parentId)) {
            throw new Error(`Moving task would create a circular reference`);
          }
        }
      }
    
      this.data.tasks[index] = { ...task, ...updates };
      this.data.tasks[index].level = this.calculateTaskLevel(this.data.tasks[index]);
      await this.save();
      return this.data.tasks[index];
    }
  • Recursive helper to get all descendant task IDs, used to prevent circular hierarchy when updating parentId.
    async function getAllDescendants(storage: Storage, taskId: string): Promise<string[]> {
      const children = await storage.getTaskChildren(taskId);
      const descendants: string[] = [];
    
      for (const child of children) {
        descendants.push(child.id);
        const childDescendants = await getAllDescendants(storage, child.id);
        descendants.push(...childDescendants);
      }
    
      return descendants;
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden for behavioral disclosure. It mentions 'comprehensive updates' and 'keep your workflow current and accurate' but doesn't specify whether this is a destructive mutation, what permissions are required, whether changes are reversible, or what happens to unspecified fields. The description lacks critical behavioral context for a 13-parameter update tool with no annotation coverage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences with some redundancy ('adapt and refine tasks' and 'keep your workflow current and accurate' convey similar ideas). The second sentence about 'advanced project management capabilities including unlimited hierarchy movement' adds marketing language rather than functional clarity. While not excessively verbose, several phrases don't earn their place in a tool description.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex 13-parameter mutation tool with no annotations and no output schema, the description is inadequate. It doesn't address critical context like error conditions, what happens when only some fields are provided, whether updates are atomic, or what the response contains. The description fails to compensate for the lack of structured metadata about this significant update operation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all 13 parameters thoroughly. The description lists categories of updatable fields (dependencies, priorities, complexity, status, tags, time tracking) which aligns with parameters like 'dependsOn', 'priority', 'complexity', 'status', 'tags', 'actualHours', and 'estimatedHours'. However, it doesn't add meaningful semantic context beyond what the schema already provides, maintaining the baseline score.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose as 'adapt and refine tasks with comprehensive updates' and lists specific updateable fields (dependencies, priorities, complexity, status, tags, time tracking). It distinguishes from sibling tools like 'create_task' by focusing on updates rather than creation, though it doesn't explicitly contrast with 'update_subtask' or 'move_task' which share similar update functionality.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives like 'update_subtask', 'move_task', or 'delete_task'. It mentions 'advanced project management capabilities including unlimited hierarchy movement' but doesn't clarify when hierarchy movement should be done via this tool versus the dedicated 'move_task' sibling tool. No prerequisites or exclusions are stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Related Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Pimzino/agentic-tools-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server