aide_discover
Scan your project for .aide spec files to reveal intent architecture. Use without a path for a project-wide map, or with a path to drill into a directory and view the ancestor chain with summaries.
Instructions
Scan for .aide spec files in this project. Returns a tree map of where specs live, following progressive disclosure.
Without a path: returns a lightweight project-wide map — file locations and types only, no content. Use this once to understand the project's spec architecture.
With a path: the response opens with the ancestor chain — the cascading intent lineage from project root down to the target directory, with each ancestor showing its description and alignment status (aligned/misaligned when set). The ancestor chain gives you the full inherited context before you read a single spec body. After the ancestor chain comes the detailed subtree of the target directory — summaries extracted from file content and anomaly warnings. Use this to drill into the area you're working on.
.aide files are progressive disclosure specs that live next to orchestrator code — they contain intent (strategy, implementation contracts, anti-patterns), research (sources, data, patterns), or QA checklists (todo). Read .aide files BEFORE reading code — they are the context layer between folder structure and implementation details.
File types (.aide, intent.aide, research.aide, plan.aide, todo.aide):
.aide — Intent spec (default). Strategy, contracts, anti-patterns.
intent.aide — Same as .aide, used only when research.aide exists in the same folder.
research.aide — Raw research. Sources, data points, pattern synthesis.
plan.aide -- Architect's implementation plan. Checkboxed steps for the implementor.
todo.aide — QA re-alignment document. Captures where implementation drifted from intent.
Never have both .aide and intent.aide in the same folder.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | Subdirectory to drill into. When provided, the response opens with the ancestor chain — the cascading intent lineage from root to target, each ancestor showing its description and alignment status — followed by the detailed subtree with summaries and warnings. When omitted, returns a shallow project-wide map (locations and types only). |
Implementation Reference
- src/tools/discover/index.ts:23-57 (handler)The main handler function for the aide_discover tool. Scans for .aide files, builds a tree map, optionally adds ancestor chain and anomaly warnings.
export default async function discover(root: string, path?: string): Promise<string> { const shallow = !path; const result = await scan(root, path, shallow); const { files } = result; if (files.length === 0) { return "No .aide files found." + (path ? ` (searched in ${path})` : ""); } const projectName = basename(root); const header = `${projectName} project — ${files.length} spec${files.length === 1 ? "" : "s"} found`; const tree = buildTree(files, root); // Only run anomaly detection and ancestor chain on deep (scoped) scans let ancestorChain = ""; let warningBlock = ""; if (!shallow) { ancestorChain = await buildAncestorChain(root, join(root, path)); const anomalies = await detectAnomalies(files, root); if (anomalies.length > 0) { const lines = anomalies.map((w) => ` ${w.path} — ${w.message}`); warningBlock = `\n\n⚠ Warnings:\n${lines.join("\n")}`; } } // Build output: header + optional ancestor chain + tree + optional warnings // Each block separated by a blank line when present const parts: string[] = [header]; if (ancestorChain) parts.push(ancestorChain); parts.push(tree); return parts.join("\n\n") + warningBlock; } - src/tools/discover/index.ts:8-10 (schema)Zod schema for the aide_discover tool input — accepts an optional 'path' string parameter.
export const DiscoverInput = z.object({ path: z.string().optional().describe("Subdirectory to scan (defaults to entire project)"), }); - src/index.ts:82-95 (registration)Tool registration in ListToolsRequestSchema — defines the tool name, description, and inputSchema for aide_discover.
name: "aide_discover", description: "Scan for .aide spec files in this project. Returns a tree map of where specs live, following progressive disclosure.\n\nWithout a path: returns a lightweight project-wide map — file locations and types only, no content. Use this once to understand the project's spec architecture.\n\nWith a path: the response opens with the ancestor chain — the cascading intent lineage from project root down to the target directory, with each ancestor showing its description and alignment status (aligned/misaligned when set). The ancestor chain gives you the full inherited context before you read a single spec body. After the ancestor chain comes the detailed subtree of the target directory — summaries extracted from file content and anomaly warnings. Use this to drill into the area you're working on.\n\n.aide files are progressive disclosure specs that live next to orchestrator code — they contain intent (strategy, implementation contracts, anti-patterns), research (sources, data, patterns), or QA checklists (todo). Read .aide files BEFORE reading code — they are the context layer between folder structure and implementation details.\n\nFile types (.aide, intent.aide, research.aide, plan.aide, todo.aide):\n- .aide — Intent spec (default). Strategy, contracts, anti-patterns.\n- intent.aide — Same as .aide, used only when research.aide exists in the same folder.\n- research.aide — Raw research. Sources, data points, pattern synthesis.\n- plan.aide -- Architect's implementation plan. Checkboxed steps for the implementor.\n- todo.aide — QA re-alignment document. Captures where implementation drifted from intent.\n\nNever have both .aide and intent.aide in the same folder.", inputSchema: { type: "object" as const, properties: { path: { type: "string", description: "Subdirectory to drill into. When provided, the response opens with the ancestor chain — the cascading intent lineage from root to target, each ancestor showing its description and alignment status — followed by the detailed subtree with summaries and warnings. When omitted, returns a shallow project-wide map (locations and types only).", }, }, }, }, - src/index.ts:251-255 (registration)Tool call handler in CallToolRequestSchema — routes 'aide_discover' to the discover function via switch statement.
case "aide_discover": { const parsed = DiscoverInput.parse(args); const result = await discover(root, parsed.path); return { content: [{ type: "text", text: result }] }; } - Builds the ancestor chain — walks from target directory up to root, collecting .aide spec metadata (description, status) for each level.
export default async function buildAncestorChain(root: string, targetPath: string): Promise<string> { // Normalize to absolute paths const absRoot = root.replace(/\\/g, "/"); const absTarget = targetPath.replace(/\\/g, "/"); // No ancestors when the target IS the root if (absTarget === absRoot) return ""; /** Walk upward from target's parent to root, collecting directory levels. */ const levels: string[] = []; let current = dirname(absTarget); while (true) { levels.push(current); if (current === absRoot) break; const parent = dirname(current); // Guard against hitting the filesystem root (should not happen in practice) if (parent === current) break; current = parent; } // levels is ordered target-parent → root; reverse for root-first rendering levels.reverse(); /** Try to read a file, returning null if it does not exist. */ async function tryRead(filePath: string): Promise<string | null> { try { return await readFile(filePath, "utf-8"); } catch { return null; } } /** Resolve which spec file to use at a given directory level, if any. */ async function resolveSpec(dir: string): Promise<{ specPath: string; content: string } | null> { const isRoot = dir === absRoot; if (isRoot) { // Root-level spec lives at .aide/intent.aide per AIDE placement rules const rootSpec = join(dir, ".aide", "intent.aide"); const content = await tryRead(rootSpec); if (content !== null) return { specPath: rootSpec, content }; return null; } // Non-root: check .aide first, then intent.aide const dotAide = join(dir, ".aide"); const intentAide = join(dir, "intent.aide"); const dotAideContent = await tryRead(dotAide); if (dotAideContent !== null) return { specPath: dotAide, content: dotAideContent }; const intentAideContent = await tryRead(intentAide); if (intentAideContent !== null) return { specPath: intentAide, content: intentAideContent }; return null; } const lines: string[] = []; for (const dir of levels) { const spec = await resolveSpec(dir); if (!spec) continue; const { frontmatter, parseError } = parseFrontmatter(spec.content); const description = frontmatter?.description || (frontmatter?.intent ? frontmatter.intent.split(/[.\n]/)[0] : undefined); const status = frontmatter?.status; // Compute a display path relative to the project root const rel = relative(absRoot, spec.specPath).replace(/\\/g, "/"); const displayPath = rel || spec.specPath; let line = ` ${displayPath}`; if (description) { line += ` — ${description}`; } // Status badge renders whenever set, regardless of whether description is present if (status === "aligned" || status === "misaligned") { line += ` [${status}]`; } if (parseError) { line += ` ⚠ YAML parse error: ${parseError}`; } // If no description and no status, show path alone (no em-dash, no fabrication) lines.push(line); } if (lines.length === 0) return ""; return `Ancestor chain:\n${lines.join("\n")}`; } - Builds a progressive disclosure tree string from discovered .aide files, grouped by directory with type tags and summaries.
export default function buildTree(files: AideFile[], root: string): string { if (files.length === 0) return ""; const groups = groupByDir(files); const sortedDirs = [...groups.keys()].sort(); const lines: string[] = []; for (let d = 0; d < sortedDirs.length; d++) { const dir = sortedDirs[d]; const dirFiles = sortFiles(groups.get(dir)!); // Directory header lines.push(`${dir}/`); for (let f = 0; f < dirFiles.length; f++) { const file = dirFiles[f]; const isLastFile = f === dirFiles.length - 1; const connector = isLastFile ? "└──" : "├──"; const name = basename(file.relativePath); const tag = `[${file.type}]`; const label = file.type === "intent" || file.type === "research" ? file.description || "" : file.summary || ""; const summary = label ? ` — ${label}` : ""; const parseWarn = file.parseError ? ` ⚠ YAML parse error: ${file.parseError}` : ""; lines.push(` ${connector} ${name} ${tag}${summary}${parseWarn}`); } if (d < sortedDirs.length - 1) lines.push(""); } return lines.join("\n"); }