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';

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