Skip to main content
Glama

overseer.check_compliance

Validate repository structure against sentinel.yml conventions to ensure compliance with expected directories and key files.

Instructions

Validates repository structure against sentinel.yml conventions. Checks for expected directories and key files.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
repo_rootYesRoot path of the repository
phase_idNoOptional: Specific phase ID to check
strictNoIf true, all checks must pass. If false, warns about missing items.

Implementation Reference

  • The core handler function implementing the overseer.check_compliance tool logic. It validates the repository against conventions from sentinel.yml, checking directories, key files, PHASES.md, phase-specific structures, and naming.
    export async function handleCheckCompliance(
      args: {
        repo_root: string;
        phase_id?: string;
        strict?: boolean;
      },
      phaseManager: PhaseManager
    ): Promise<{
      success: boolean;
      compliant: boolean;
      phase_id?: string;
      checks: Array<{
        check_type: 'directory' | 'file' | 'convention' | 'phase_structure';
        passed: boolean;
        message: string;
        details?: Record<string, unknown>;
      }>;
      summary: {
        total_checks: number;
        passed: number;
        failed: number;
      };
    }> {
      const checks: Array<{
        check_type: 'directory' | 'file' | 'convention' | 'phase_structure';
        passed: boolean;
        message: string;
        details?: Record<string, unknown>;
      }> = [];
    
      try {
        // Resolve repo path
        let repoPath = args.repo_root;
        if (!repoPath.startsWith('/')) {
          repoPath = join(homedir(), 'dev', repoPath);
        }
        repoPath = FSUtils.expandPath(repoPath);
    
        if (!FSUtils.dirExists(repoPath)) {
          return {
            success: false,
            compliant: false,
            checks: [{
              check_type: 'directory',
              passed: false,
              message: 'Repository directory does not exist',
            }],
            summary: {
              total_checks: 1,
              passed: 0,
              failed: 1,
            },
          };
        }
    
        // Load config to get conventions
        const configLoader = new ConfigLoader();
        const config = configLoader.getConfig();
        const conventions = config.conventions;
    
        // Check PHASES.md exists
        const phasesPath = join(repoPath, conventions.phases_index.file);
        if (FSUtils.fileExists(phasesPath)) {
          checks.push({
            check_type: 'file',
            passed: true,
            message: `${conventions.phases_index.file} exists`,
          });
        } else {
          checks.push({
            check_type: 'file',
            passed: false,
            message: `${conventions.phases_index.file} is missing`,
          });
        }
    
        // Check for common expected directories based on conventions
        const expectedDirs = ['src', 'config', 'docs'];
        for (const dir of expectedDirs) {
          const dirPath = join(repoPath, dir);
          if (FSUtils.dirExists(dirPath)) {
            checks.push({
              check_type: 'directory',
              passed: true,
              message: `${dir}/ directory exists`,
            });
          } else {
            checks.push({
              check_type: 'directory',
              passed: false,
              message: `${dir}/ directory is missing`,
            });
          }
        }
    
        // Check for key files
        const keyFiles = ['README.md', 'package.json', '.gitignore'];
        for (const file of keyFiles) {
          const filePath = join(repoPath, file);
          if (FSUtils.fileExists(filePath)) {
            checks.push({
              check_type: 'file',
              passed: true,
              message: `${file} exists`,
            });
          } else {
            checks.push({
              check_type: 'file',
              passed: false,
              message: `${file} is missing`,
            });
          }
        }
    
        // If phase_id provided, check phase-specific structure
        if (args.phase_id) {
          const phaseId = args.phase_id.padStart(2, '0');
          const phaseFilePath = join(repoPath, `PHASE-${phaseId}.md`);
          
          if (FSUtils.fileExists(phaseFilePath)) {
            const phaseContent = FSUtils.readFile(phaseFilePath);
            
            // Check for required sections
            const requiredSections = ['Description', 'Deliverables', 'Done Criteria', 'Progress'];
            for (const section of requiredSections) {
              if (phaseContent.includes(`## ${section}`)) {
                checks.push({
                  check_type: 'phase_structure',
                  passed: true,
                  message: `PHASE-${phaseId}.md has ${section} section`,
                });
              } else {
                checks.push({
                  check_type: 'phase_structure',
                  passed: false,
                  message: `PHASE-${phaseId}.md missing ${section} section`,
                });
              }
            }
          } else {
            checks.push({
              check_type: 'phase_structure',
              passed: false,
              message: `PHASE-${phaseId}.md file is missing`,
            });
          }
        }
    
        // Check naming conventions
        const repoName = repoPath.split('/').pop() || '';
        const namingConvention = conventions.naming.phase_names; // Use phase_names as proxy for repo naming
        if (namingConvention === 'kebab-case') {
          const isValidKebabCase = /^[a-z0-9]+(-[a-z0-9]+)*$/.test(repoName);
          checks.push({
            check_type: 'convention',
            passed: isValidKebabCase,
            message: `Repository name follows kebab-case convention`,
            details: { repo_name: repoName, expected_format: 'kebab-case' },
          });
        }
    
        // Calculate summary
        const passed = checks.filter(c => c.passed).length;
        const failed = checks.filter(c => !c.passed).length;
        const compliant = args.strict ? failed === 0 : true; // In strict mode, all must pass
    
        return {
          success: true,
          compliant,
          phase_id: args.phase_id,
          checks,
          summary: {
            total_checks: checks.length,
            passed,
            failed,
          },
        };
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        return {
          success: false,
          compliant: false,
          checks: [{
            check_type: 'convention',
            passed: false,
            message: `Error checking compliance: ${errorMessage}`,
          }],
          summary: {
            total_checks: 1,
            passed: 0,
            failed: 1,
          },
        };
      }
    }
  • Defines the tool specification including name, description, and detailed inputSchema for parameters repo_root (required), phase_id (optional), strict (optional boolean).
    export function createCheckComplianceTool(phaseManager: PhaseManager): Tool {
      return {
        name: 'overseer.check_compliance',
        description: 'Validates repository structure against sentinel.yml conventions. Checks for expected directories and key files.',
        inputSchema: {
          type: 'object',
          required: ['repo_root'],
          properties: {
            repo_root: {
              type: 'string',
              description: 'Root path of the repository',
            },
            phase_id: {
              type: 'string',
              description: 'Optional: Specific phase ID to check',
            },
            strict: {
              type: 'boolean',
              default: false,
              description: 'If true, all checks must pass. If false, warns about missing items.',
            },
          },
        },
      };
    }
  • Tool factory function that registers the overseer.check_compliance tool by calling createCheckComplianceTool and including it in the array of available tools.
    export function createTools(context: ToolContext): Tool[] {
      return [
        // Planning tools
        createPlanProjectTool(context.phaseManager),
        createInferPhasesTool(context.configLoader),
        createUpdatePhasesTool(context.phaseManager),
        // Execution tools
        createRunPhaseTool(context.phaseManager),
        createAdvancePhaseTool(context.phaseManager),
        createStatusTool(context.phaseManager),
        // QA tools
        createLintRepoTool(context.configLoader),
        createSyncDocsTool(context.phaseManager),
        createCheckComplianceTool(context.phaseManager),
        // Environment tools
        createEnvMapTool(context.phaseManager),
        createGenerateCiTool(context.phaseManager),
        createSecretsTemplateTool(context.phaseManager),
      ];
    }
  • Central tool dispatcher that routes calls to 'overseer.check_compliance' to the handleCheckCompliance function with context.
    export async function handleToolCall(
      name: string,
      args: any,
      context: ToolContext
    ): Promise<any> {
      switch (name) {
        // Planning tools
        case 'overseer.plan_project':
          return await handlePlanProject(args, context.phaseManager);
        case 'overseer.infer_phases':
          return await handleInferPhases(args, context.configLoader);
        case 'overseer.update_phases':
          return await handleUpdatePhases(args, context.phaseManager);
        // Execution tools
        case 'overseer.run_phase':
          return await handleRunPhase(args, context.phaseManager);
        case 'overseer.advance_phase':
          return await handleAdvancePhase(args, context.phaseManager);
        case 'overseer.status':
          return await handleStatus(args, context.phaseManager);
        // QA tools
        case 'overseer.lint_repo':
          return await handleLintRepo(args, context.configLoader);
        case 'overseer.sync_docs':
          return await handleSyncDocs(args, context.phaseManager);
        case 'overseer.check_compliance':
          return await handleCheckCompliance(args, context.phaseManager);
        // Environment tools
        case 'overseer.env_map':
          return await handleEnvMap(args, context.phaseManager);
        case 'overseer.generate_ci':
          return await handleGenerateCi(args, context.phaseManager);
        case 'overseer.secrets_template':
          return await handleSecretsTemplate(args, context.phaseManager);
        default:
          throw new Error(`Unknown tool: ${name}`);
      }
    }

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