get_codebase_health
Retrieve actionable codebase health signals to identify highest-risk files with reasons. Optionally inspect a single file's health record.
Instructions
Routes to the active/current project automatically when known. Get actionable codebase health signals from the latest index. Returns the highest-risk files and their reasons, or a single file when requested.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| file | No | Optional file path to inspect a single file-level health record. | |
| limit | No | Maximum number of files to return when no file is specified (default: 10). | |
| level | No | Optional minimum health level to return. | |
| project | No | Optional project selector for this call. Accepts a project root path, file path, file:// URI, or a relative subproject path under a configured root. | |
| project_directory | No | Deprecated compatibility alias for older clients. Prefer project. |
Implementation Reference
- src/tools/get-codebase-health.ts:30-112 (handler)Main handler function for the 'get_codebase_health' tool. Reads the health artifact file, optionally filters by a single file or by risk level/limit, and returns formatted JSON responses.
export async function handle( args: Record<string, unknown>, ctx: ToolContext ): Promise<ToolResponse> { const file = typeof args.file === 'string' ? args.file.trim() : undefined; const limit = typeof args.limit === 'number' && Number.isFinite(args.limit) ? args.limit : 10; const level = args.level === 'low' || args.level === 'medium' || args.level === 'high' ? args.level : undefined; const health = await readHealthFile(ctx.paths.health); if (!health) { return { content: [ { type: 'text', text: JSON.stringify( { status: 'no_data', message: 'No codebase health artifact found. Run refresh_index to generate health.json.' }, null, 2 ) } ] }; } const orderedLevels = { high: 3, medium: 2, low: 1 }; const minLevel = level ? orderedLevels[level] : 1; if (file) { const byFile = indexHealthByFile(health, ctx.rootPath); const fileHealth = byFile.get(normalizeHealthLookupKey(file, ctx.rootPath)); return { content: [ { type: 'text', text: JSON.stringify( fileHealth ? { status: 'success', generatedAt: health.generatedAt, file: fileHealth } : { status: 'not_found', message: `No health record found for ${file}.`, generatedAt: health.generatedAt }, null, 2 ) } ] }; } const files = health.files .filter((entry) => orderedLevels[entry.level] >= minLevel) .slice(0, Math.max(1, Math.floor(limit))); return { content: [ { type: 'text', text: JSON.stringify( { status: 'success', generatedAt: health.generatedAt, summary: health.summary, files }, null, 2 ) } ] }; } - Tool definition with inputSchema for get_codebase_health. Accepts optional 'file' (string), 'limit' (number, default 10), and 'level' (enum: low/medium/high).
export const definition: Tool = { name: 'get_codebase_health', description: 'Get actionable codebase health signals from the latest index. Returns the highest-risk files and their reasons, or a single file when requested.', inputSchema: { type: 'object', properties: { file: { type: 'string', description: 'Optional file path to inspect a single file-level health record.' }, limit: { type: 'number', description: 'Maximum number of files to return when no file is specified (default: 10).', default: 10 }, level: { type: 'string', enum: ['low', 'medium', 'high'], description: 'Optional minimum health level to return.' } } } }; - src/tools/index.ts:55-57 (registration)Tool registered in the TOOLS array (as d11) and dispatched via switch-case at line 85-86.
export const TOOLS: Tool[] = [d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11].map( withProjectSelector ); - src/health/store.ts:95-127 (helper)Helper functions: readHealthFile reads and validates the health.json artifact, normalizeHealthLookupKey normalizes file paths for lookup, and indexHealthByFile builds a Map for O(1) file access.
export async function readHealthFile(healthPath: string): Promise<CodebaseHealthArtifact | null> { try { const content = await fs.readFile(healthPath, 'utf-8'); return normalizeHealthArtifact(JSON.parse(content)); } catch { return null; } } export function normalizeHealthLookupKey(filePath: string, rootPath?: string): string { const normalized = filePath.replace(/\\/g, '/').replace(/^\.\//, ''); if (!rootPath) { return normalized; } const normalizedRoot = rootPath.replace(/\\/g, '/').replace(/\/$/, ''); if (normalized.startsWith(normalizedRoot)) { return normalized.slice(normalizedRoot.length).replace(/^\//, ''); } return normalized; } export function indexHealthByFile( artifact: CodebaseHealthArtifact | null, rootPath?: string ): Map<string, CodebaseHealthFile> { const map = new Map<string, CodebaseHealthFile>(); if (!artifact) return map; for (const fileHealth of artifact.files) { map.set(normalizeHealthLookupKey(fileHealth.file, rootPath), fileHealth); } return map; } - src/health/derive.ts:168-207 (helper)deriveCodebaseHealth generates the health artifact from code chunks and dependency graph, computing risk levels (high/medium/low) based on metrics like cycle count, fan-in, hotspot rank, and cyclomatic complexity.
export function deriveCodebaseHealth({ buildId, formatVersion, generatedAt, chunks, graph }: DeriveCodebaseHealthParams): CodebaseHealthArtifact { const fileMetrics = collectFileMetrics(chunks, graph); const files = Array.from(fileMetrics.entries()) .map(([file, metrics]) => { const health = getHealthLevel(metrics); return { ...health, file }; }) .sort((a, b) => { const priority = { high: 0, medium: 1, low: 2 }; const levelDelta = priority[a.level] - priority[b.level]; if (levelDelta !== 0) return levelDelta; if (b.score !== a.score) return b.score - a.score; return a.file.localeCompare(b.file); }); const highRiskFiles = files.filter((file) => file.level === 'high').length; const mediumRiskFiles = files.filter((file) => file.level === 'medium').length; const lowRiskFiles = files.length - highRiskFiles - mediumRiskFiles; return { header: { buildId, formatVersion }, generatedAt, summary: { files: files.length, highRiskFiles, mediumRiskFiles, lowRiskFiles }, files }; }