Skip to main content
Glama

overseer.update_phases

Modify phase definitions in project workflows by renaming, updating descriptions, or adjusting steps, deliverables, and completion criteria.

Instructions

Updates existing phase definitions (rename, modify description, add/remove steps, deliverables, done criteria).

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
repo_rootYesRoot path of the repository
modificationsYesList of modifications to apply

Implementation Reference

  • The main handler function that executes the tool logic: reads existing phases from PHASES.md, applies modifications (add, update, remove), and writes updated phases back to the file.
    export async function handleUpdatePhases(
      args: {
        repo_root: string;
        modifications: Array<{
          operation: 'add' | 'update' | 'remove';
          phase_id?: string;
          phase?: {
            id: string;
            name: string;
            description: string;
            deliverables?: string[];
            done_criteria?: string[];
          };
        }>;
      },
      phaseManager: PhaseManager
    ): Promise<{
      success: boolean;
      message: string;
      changes_applied: {
        added: string[];
        updated: string[];
        removed: string[];
      };
      files_written: string[];
      errors: string[];
    }> {
      const errors: string[] = [];
      const added: string[] = [];
      const updated: string[] = [];
      const removed: string[] = [];
      const filesWritten: string[] = [];
    
      try {
        // Resolve repo path
        let repoPath = args.repo_root;
        if (!repoPath.startsWith('/')) {
          repoPath = join(homedir(), 'dev', repoPath);
        }
        repoPath = FSUtils.expandPath(repoPath);
    
        // Extract repo name from path
        const repoName = repoPath.split('/').pop() || 'unknown';
    
        // Read existing phases
        // We need to create a RepoHandler that can read from the absolute path
        // For now, let's read directly and parse
        const phasesPath = join(repoPath, 'PHASES.md');
        if (!FSUtils.fileExists(phasesPath)) {
          return {
            success: false,
            message: 'Project not found. Run plan_project first.',
            changes_applied: { added: [], updated: [], removed: [] },
            files_written: [],
            errors: ['PHASES.md not found'],
          };
        }
    
        // Use RepoHandler with absolute path (handles paths with spaces)
        const repoHandler = new RepoHandler();
        let projectPhases = repoHandler.readPhasesIndexFromPath(repoPath);
        
        if (!projectPhases) {
          return {
            success: false,
            message: 'Project not found. Run plan_project first.',
            changes_applied: { added: [], updated: [], removed: [] },
            files_written: [],
            errors: ['PHASES.md not found'],
          };
        }
    
        // Apply modifications
        for (const mod of args.modifications) {
          try {
            if (mod.operation === 'add') {
              if (!mod.phase) {
                errors.push('Phase data required for add operation');
                continue;
              }
    
              // Validate required fields
              if (!mod.phase.id || !mod.phase.name || !mod.phase.description) {
                errors.push('Phase must have id, name, and description');
                continue;
              }
    
              // Check if phase ID already exists
              if (projectPhases.phases.some(p => p.id === mod.phase!.id)) {
                errors.push(`Phase ID ${mod.phase.id} already exists`);
                continue;
              }
    
              // Add phase
              const newPhase: PhaseInfo = {
                id: mod.phase.id,
                name: mod.phase.name,
                status: 'pending',
                description: mod.phase.description,
                deliverables: mod.phase.deliverables,
                done_criteria: mod.phase.done_criteria,
              };
    
              projectPhases.phases.push(newPhase);
              added.push(mod.phase.id);
    
            } else if (mod.operation === 'update') {
              if (!mod.phase_id) {
                errors.push('phase_id required for update operation');
                continue;
              }
    
              const phaseIndex = projectPhases.phases.findIndex(p => p.id === mod.phase_id);
              if (phaseIndex === -1) {
                errors.push(`Phase ID ${mod.phase_id} not found`);
                continue;
              }
    
              if (!mod.phase) {
                errors.push('Phase data required for update operation');
                continue;
              }
    
              // Update phase
              const existingPhase = projectPhases.phases[phaseIndex];
              projectPhases.phases[phaseIndex] = {
                ...existingPhase,
                name: mod.phase.name || existingPhase.name,
                description: mod.phase.description || existingPhase.description,
                deliverables: mod.phase.deliverables !== undefined ? mod.phase.deliverables : existingPhase.deliverables,
                done_criteria: mod.phase.done_criteria !== undefined ? mod.phase.done_criteria : existingPhase.done_criteria,
              };
    
              updated.push(mod.phase_id);
    
            } else if (mod.operation === 'remove') {
              if (!mod.phase_id) {
                errors.push('phase_id required for remove operation');
                continue;
              }
    
              const phaseIndex = projectPhases.phases.findIndex(p => p.id === mod.phase_id);
              if (phaseIndex === -1) {
                errors.push(`Phase ID ${mod.phase_id} not found`);
                continue;
              }
    
              projectPhases.phases.splice(phaseIndex, 1);
              removed.push(mod.phase_id);
            }
          } catch (error) {
            const errorMsg = error instanceof Error ? error.message : String(error);
            errors.push(`Failed to apply modification: ${errorMsg}`);
          }
        }
    
        // Write updated PHASES.md
        if (added.length > 0 || updated.length > 0 || removed.length > 0) {
          try {
            repoHandler.writePhasesIndexToPath(repoPath, projectPhases);
            filesWritten.push(join(repoPath, 'PHASES.md'));
          } catch (error) {
            errors.push(`Failed to write PHASES.md: ${error}`);
          }
        }
    
        const success = errors.length === 0;
        const message = success
          ? `Applied ${added.length} additions, ${updated.length} updates, ${removed.length} removals`
          : `Partially applied changes with ${errors.length} error(s)`;
    
        return {
          success,
          message,
          changes_applied: {
            added,
            updated,
            removed,
          },
          files_written: filesWritten,
          errors,
        };
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        return {
          success: false,
          message: `Failed to update phases: ${errorMessage}`,
          changes_applied: { added: [], updated: [], removed: [] },
          files_written: [],
          errors: [errorMessage],
        };
      }
    }
  • Defines the tool schema including name, description, and detailed inputSchema for modifications.
    export function createUpdatePhasesTool(phaseManager: PhaseManager): Tool {
      return {
        name: 'overseer.update_phases',
        description: 'Updates existing phase definitions (rename, modify description, add/remove steps, deliverables, done criteria).',
        inputSchema: {
          type: 'object',
          required: ['repo_root', 'modifications'],
          properties: {
            repo_root: {
              type: 'string',
              description: 'Root path of the repository',
            },
            modifications: {
              type: 'array',
              items: {
                type: 'object',
                properties: {
                  operation: {
                    type: 'string',
                    enum: ['add', 'update', 'remove'],
                    description: 'Operation to perform',
                  },
                  phase_id: {
                    type: 'string',
                    description: 'Phase ID to update or remove (required for update/remove)',
                  },
                  phase: {
                    type: 'object',
                    description: 'Phase data (required for add/update)',
                    properties: {
                      id: { type: 'string' },
                      name: { type: 'string' },
                      description: { type: 'string' },
                      deliverables: {
                        type: 'array',
                        items: { type: 'string' },
                      },
                      done_criteria: {
                        type: 'array',
                        items: { type: 'string' },
                      },
                    },
                  },
                },
                required: ['operation'],
              },
              description: 'List of modifications to apply',
            },
          },
        },
      };
    }
  • Tool handler registration in the central switch dispatcher in handleToolCall.
    case 'overseer.update_phases':
      return await handleUpdatePhases(args, context.phaseManager);
  • Tool creation and registration in the createTools array.
    createUpdatePhasesTool(context.phaseManager),
  • src/tools/index.ts:9-9 (registration)
    Import of the tool creator and handler from update-phases.ts.
    import { createUpdatePhasesTool, handleUpdatePhases } from './update-phases.js';
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. While 'Updates' implies mutation, it doesn't describe permissions needed, whether changes are reversible, error handling (e.g., invalid phase_id), or what happens on success/failure. For a mutation tool with zero annotation coverage, this leaves significant behavioral gaps unaddressed.

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

Conciseness4/5

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

The description is a single, efficient sentence that packs substantial information about what can be modified. It's front-loaded with the core action and provides specific examples without unnecessary elaboration. Every word earns its place, though it could potentially be more structured for readability.

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 mutation tool with no annotations and no output schema, the description is incomplete. It doesn't address behavioral aspects like permissions, side effects, or response format. While the purpose is clear, the lack of usage guidance and behavioral transparency makes it inadequate for safe and effective tool selection by an AI agent.

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 both parameters (repo_root, modifications) thoroughly. The description adds no parameter-specific information beyond what's in the schema - it doesn't explain parameter relationships, format examples, or constraints. Baseline 3 is appropriate when schema does the heavy lifting.

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 verb ('Updates') and resource ('existing phase definitions'), with specific examples of what can be modified (rename, modify description, add/remove steps, deliverables, done criteria). It distinguishes from siblings like overseer.advance_phase or overseer.run_phase by focusing on definition modification rather than execution. However, it doesn't explicitly differentiate from overseer.infer_phases which might also modify phases.

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. It doesn't mention prerequisites (e.g., existing phases to modify), when-not-to-use scenarios, or comparisons with siblings like overseer.infer_phases (which might create phases) or overseer.plan_project (which might involve phase planning). Usage is implied but not explicitly 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

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/freqkflag/PROJECT-OVERSEER-MCP'

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