Skip to main content
Glama

overseer.plan_project

Plan software projects by creating phase definitions and documentation files. Generates PHASES.md and phase-specific files, optionally inferring structure from existing repositories.

Instructions

Plan a new project by creating phase definitions. Creates PHASES.md and PHASE-*.md files in the repository. Can infer phases from project structure if not provided.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
repo_rootYesRoot path of the repository (absolute path or relative to ~/dev)
project_nameYesName of the project
project_summaryNoSummary description of the project
overwrite_existingNoIf true, overwrite existing PHASES.md. If false, normalize and merge.
phasesNoOptional: Explicit phase definitions. If not provided, phases will be inferred.

Implementation Reference

  • The main execution handler for the 'overseer.plan_project' tool. It resolves the repository path, infers or uses provided phases, generates and writes PHASES.md and individual PHASE-*.md files, handling overwrites and errors.
    export async function handlePlanProject(
      args: {
        repo_root: string;
        project_name: string;
        project_summary?: string;
        overwrite_existing?: boolean;
        phases?: Array<{
          id: string;
          name: string;
          description: string;
          deliverables?: string[];
          done_criteria?: string[];
        }>;
      },
      phaseManager: PhaseManager
    ): Promise<{
      success: boolean;
      message: string;
      phases_discovered: number;
      phases_created: number;
      files_written: string[];
      files_updated: string[];
      errors: string[];
    }> {
      const errors: string[] = [];
      const filesWritten: string[] = [];
      const filesUpdated: string[] = [];
    
      try {
        // Resolve repo path
        let repoPath = args.repo_root;
        if (!repoPath.startsWith('/')) {
          // Relative path - resolve from ~/dev
          repoPath = join(homedir(), 'dev', repoPath);
        }
        repoPath = FSUtils.expandPath(repoPath);
    
        // Ensure repo exists
        FSUtils.ensureDir(repoPath);
    
        // Check if PHASES.md exists
        const phasesPath = join(repoPath, 'PHASES.md');
        const phasesExist = FSUtils.fileExists(phasesPath);
    
        let phases: Array<{
          id: string;
          name: string;
          description: string;
          deliverables?: string[];
          done_criteria?: string[];
        }> = [];
    
        // If phases provided explicitly, use them
        if (args.phases && args.phases.length > 0) {
          phases = args.phases;
        } else {
          // Infer phases from repo structure
          const analysis = RepoAnalyzer.analyzeRepo(repoPath, {
            detect_frameworks: true,
            detect_infrastructure: true,
          });
    
          if (analysis.suggested_phases.length > 0) {
            phases = analysis.suggested_phases.map(p => ({
              id: p.id,
              name: p.name,
              description: p.description,
              deliverables: p.deliverables,
              done_criteria: p.done_criteria,
            }));
          } else {
            // Fallback to default phases
            phases = [
              {
                id: '01',
                name: 'foundation',
                description: 'Project foundation and setup',
                deliverables: ['Project structure', 'README.md', 'Basic configuration'],
                done_criteria: ['Project structure is in place', 'README.md exists'],
              },
            ];
          }
        }
    
        // Read existing phases if they exist and we're not overwriting
        let existingPhases: any = null;
        if (phasesExist && !args.overwrite_existing) {
          try {
            const existingContent = FSUtils.readFile(phasesPath);
            // Try to parse as markdown (we'll use a simple approach for now)
            // For full parsing, we'd use the RepoHandler
            existingPhases = { exists: true, content: existingContent };
          } catch (error) {
            errors.push(`Failed to read existing PHASES.md: ${error}`);
          }
        }
    
        // Generate PHASES.md content
        const now = new Date().toISOString();
        const phasesContent = generatePhasesMarkdown(
          args.project_name,
          phases,
          existingPhases ? now : now, // created_at
          now, // updated_at
          existingPhases ? 'updated' : 'created'
        );
    
        // Write PHASES.md
        try {
          FSUtils.writeFile(phasesPath, phasesContent);
          if (phasesExist) {
            filesUpdated.push(phasesPath);
          } else {
            filesWritten.push(phasesPath);
          }
        } catch (error) {
          errors.push(`Failed to write PHASES.md: ${error}`);
        }
    
        // Generate and write PHASE-XX.md files
        for (const phase of phases) {
          const phaseFilePath = join(repoPath, `PHASE-${phase.id.padStart(2, '0')}.md`);
          const phaseContent = generatePhaseFileContent(phase, args.project_name);
    
          try {
            const phaseExists = FSUtils.fileExists(phaseFilePath);
            FSUtils.writeFile(phaseFilePath, phaseContent);
            if (phaseExists) {
              filesUpdated.push(phaseFilePath);
            } else {
              filesWritten.push(phaseFilePath);
            }
          } catch (error) {
            errors.push(`Failed to write ${phaseFilePath}: ${error}`);
          }
        }
    
        const success = errors.length === 0;
        const message = success
          ? `${phasesExist ? 'Updated' : 'Created'} project "${args.project_name}" with ${phases.length} phase(s)`
          : `Partially ${phasesExist ? 'updated' : 'created'} project with ${errors.length} error(s)`;
    
        return {
          success,
          message,
          phases_discovered: phases.length,
          phases_created: phases.length,
          files_written: filesWritten,
          files_updated: filesUpdated,
          errors,
        };
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        return {
          success: false,
          message: `Failed to plan project: ${errorMessage}`,
          phases_discovered: 0,
          phases_created: 0,
          files_written: [],
          files_updated: [],
          errors: [errorMessage],
        };
      }
    }
  • Tool factory function that returns the Tool object definition, including name, description, and detailed inputSchema for validation.
    export function createPlanProjectTool(phaseManager: PhaseManager): Tool {
      return {
        name: 'overseer.plan_project',
        description: 'Plan a new project by creating phase definitions. Creates PHASES.md and PHASE-*.md files in the repository. Can infer phases from project structure if not provided.',
        inputSchema: {
          type: 'object',
          properties: {
            repo_root: {
              type: 'string',
              description: 'Root path of the repository (absolute path or relative to ~/dev)',
            },
            project_name: {
              type: 'string',
              description: 'Name of the project',
            },
            project_summary: {
              type: 'string',
              description: 'Summary description of the project',
            },
            overwrite_existing: {
              type: 'boolean',
              default: false,
              description: 'If true, overwrite existing PHASES.md. If false, normalize and merge.',
            },
            phases: {
              type: 'array',
              items: {
                type: 'object',
                properties: {
                  id: { type: 'string' },
                  name: { type: 'string' },
                  description: { type: 'string' },
                  deliverables: {
                    type: 'array',
                    items: { type: 'string' },
                  },
                  done_criteria: {
                    type: 'array',
                    items: { type: 'string' },
                  },
                },
                required: ['id', 'name', 'description'],
              },
              description: 'Optional: Explicit phase definitions. If not provided, phases will be inferred.',
            },
          },
          required: ['repo_root', 'project_name'],
        },
      };
  • Tool handler registration in the central dispatcher switch statement within handleToolCall function.
    case 'overseer.plan_project':
      return await handlePlanProject(args, context.phaseManager);
  • Registration of the tool in the createTools array for inclusion in the tools list.
    createPlanProjectTool(context.phaseManager),
  • Helper function to generate the content for PHASES.md file from project phases.
    function generatePhasesMarkdown(
      projectName: string,
      phases: Array<{
        id: string;
        name: string;
        description: string;
        deliverables?: string[];
        done_criteria?: string[];
      }>,
      created_at: string,
      updated_at: string,
      action: 'created' | 'updated'
    ): string {
      const lines: string[] = [];
    
      lines.push(`# Project Phases: ${projectName}`);
      lines.push('');
      lines.push('This document tracks the phases of the project.');
      lines.push('');
      lines.push('## Metadata');
      lines.push('');
      lines.push(`- **Created**: ${created_at}`);
      lines.push(`- **Updated**: ${updated_at}`);
      lines.push(`- **Total Phases**: ${phases.length}`);
      lines.push('');
      lines.push('## Phases');
      lines.push('');
    
      phases.forEach((phase) => {
        lines.push(`### ${phase.id}. ${phase.name}`);
        lines.push('');
        lines.push(`**Status**: pending`);
        lines.push(`**Description**: ${phase.description}`);
        lines.push('');
    
        if (phase.deliverables && phase.deliverables.length > 0) {
          lines.push('**Deliverables**:');
          lines.push('');
          phase.deliverables.forEach(deliverable => {
            lines.push(`- ${deliverable}`);
          });
          lines.push('');
        }
    
        if (phase.done_criteria && phase.done_criteria.length > 0) {
          lines.push('**Done Criteria**:');
          lines.push('');
          phase.done_criteria.forEach(criterion => {
            lines.push(`- [ ] ${criterion}`);
          });
          lines.push('');
        }
      });
    
      lines.push('---');
      lines.push('');
      lines.push(`*This file is automatically managed by Overseer MCP.*`);
      lines.push(`*Last ${action}: ${updated_at}*`);
    
      return lines.join('\n');
    }
Behavior3/5

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

With no annotations provided, the description carries the full burden. It discloses key behavioral traits: it creates files (PHASES.md, PHASE-*.md), can infer phases if not provided, and mentions overwrite/merge behavior via the parameter description. However, it lacks details on permissions needed, error handling, or what 'normalize and merge' entails beyond the parameter hint.

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

Conciseness5/5

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

The description is front-loaded with the core purpose, followed by specific actions and a conditional behavior, all in three concise sentences with zero wasted words. Every sentence adds essential information.

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

Completeness3/5

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

For a tool with 5 parameters, no annotations, and no output schema, the description is adequate but has gaps. It covers the main action and file creation, but lacks details on error conditions, what the created files contain, or how phase inference works, leaving some behavioral aspects unclear.

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%, providing a strong baseline. The description adds marginal value by clarifying that phases are 'inferred from project structure if not provided', which gives context for the 'phases' parameter, but does not elaborate on other parameters beyond what the schema already documents.

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

Purpose5/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 with specific verbs ('Plan', 'creating phase definitions', 'Creates PHASES.md and PHASE-*.md files') and resources ('repository'), distinguishing it from siblings like overseer.infer_phases (which only infers) or overseer.update_phases (which updates existing phases).

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

Usage Guidelines4/5

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

The description provides clear context for when to use this tool ('Plan a new project') and hints at an alternative approach ('Can infer phases from project structure if not provided'), but does not explicitly state when NOT to use it or name specific sibling alternatives like overseer.update_phases for existing projects.

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