feat: add nested instruction strategy with hub + detail files#22
feat: add nested instruction strategy with hub + detail files#22digitarald merged 2 commits intomainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new nested instruction generation strategy (hub AGENTS.md + per-topic detail files in a configurable directory, plus optional CLAUDE.md transclusion) and wires it through the CLI and VS Code extension, with accompanying config parsing and expanded test coverage.
Changes:
- Introduces
InstructionStrategy(flat|nested) and config support forstrategy,detailDir,claudeMd, andparentArea(with validation). - Implements nested instruction generation + writing (
generateNested*,writeInstructionFile,writeNestedInstructions) and detection of existing nested detail files. - Updates CLI/VS Code flows to select strategy and execute nested generation; adds tests for parsing/writing/detection/config.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| vscode-extension/src/services.ts | Re-exports new analyzer/config and nested instruction services for the extension. |
| vscode-extension/src/commands/instructions.ts | Adds strategy quick pick + nested generation flow in VS Code. |
| src/services/instructions.ts | Implements nested hub/detail generation, writing helpers, and nested detail detection. |
| src/services/analyzer.ts | Extends config/types to include strategy/detailDir/claudeMd/parentArea with validation. |
| src/services/tests/instructions.test.ts | Adds tests for nested parsing/writing/detection and new writer helper. |
| src/services/tests/analyzer.test.ts | Adds tests for new config fields and validation. |
| src/commands/instructions.ts | Adds --strategy / --claude-md behavior and nested generation/write flow in CLI. |
| src/commands/generate.ts | Plumbs --strategy through primer generate ... to instructions generation. |
| src/cli.ts | Adds CLI flags for --strategy and --claude-md. |
Comments suppressed due to low confidence (2)
src/commands/instructions.ts:83
- Nested generation logs
Skipped ... (exists, use --force)for every non-"wrote" action, butwriteInstructionFile()can also skip due tosymlinkoremptycontent. With the currentwriteNestedInstructions()return shape, this message will be misleading in those cases. Either propagate a skip reason in the actions or use a more generic skip message here.
for (const action of actions) {
const relPath = path.relative(process.cwd(), action.path);
if (action.action === "wrote") {
if (shouldLog(options)) progress.succeed(`Wrote ${relPath}`);
} else if (shouldLog(options)) {
progress.update(`Skipped ${relPath} (exists, use --force)`);
}
src/services/instructions.ts:782
- Same as above: this
process.stderr.writewarning is emitted from the service regardless of--quiet/ UI context. Consider routing warnings throughonProgressor returning them so the CLI/VS Code layer controls how (or whether) they are displayed.
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
process.stderr.write(`Warning: Failed to generate detail for "${topic.title}": ${msg}\n`);
}
| async function findDetailFiles(repoPath: string, detailDirName: string): Promise<string[]> { | ||
| const detailFiles: string[] = []; | ||
| const excludeDirs = new Set([".git", "node_modules", "apm_modules", ".apm"]); | ||
|
|
||
| async function walk(dir: string, relPath: string): Promise<void> { | ||
| const entries = await fs.readdir(dir, { withFileTypes: true }).catch(() => []); | ||
| for (const entry of entries) { | ||
| if (excludeDirs.has(entry.name)) continue; | ||
| if (entry.isSymbolicLink()) continue; | ||
| if (entry.isDirectory()) { | ||
| if (entry.name === detailDirName) { | ||
| // Found a detail directory — list .md files inside | ||
| const detailDir = path.join(dir, entry.name); |
There was a problem hiding this comment.
detailDir is treated as a single directory name (entry.name === detailDirName). However, loadAgentrcConfig() allows values containing / (e.g. docs/ai). In that case, existing detail files won’t be detected. Either constrain detailDir to a single path segment during config validation, or update findDetailFiles() to handle multi-segment relative paths.
| areas.push({ | ||
| name: e.name as string, | ||
| applyTo, | ||
| description: typeof e.description === "string" ? e.description : undefined | ||
| description: typeof e.description === "string" ? e.description : undefined, | ||
| parentArea: typeof e.parentArea === "string" ? e.parentArea : undefined | ||
| }); |
There was a problem hiding this comment.
loadAgentrcConfig() now parses parentArea, but the analyzed Area objects used by CLI/extension appear to never receive this field (searching src/services/analyzer.ts shows no other parentArea assignments). As a result, downstream logic like areas.filter((a) => a.parentArea === area.name) and hub parentContext will never work. Ensure detectAreas()/the config-area→Area mapping propagates parentArea onto Area objects.
src/services/instructions.ts
Outdated
| const progress = options.onProgress ?? (() => {}); | ||
| const model = options.model ?? DEFAULT_MODEL; | ||
|
|
||
| const existingCtx = await detectExistingInstructions(options.repoPath); |
There was a problem hiding this comment.
generateNestedHub() calls detectExistingInstructions(options.repoPath) without passing the configured detailDir. If detailDir is customized (e.g. docs-ai), existing nested detail files won’t be detected and the hub prompt can duplicate content. Pass options.detailDir as the detailDirName argument so detection matches the strategy output directory.
| const existingCtx = await detectExistingInstructions(options.repoPath); | |
| const existingCtx = await detectExistingInstructions(options.repoPath, options.detailDir); |
…ction status, warnings
Summary
Adds a nested instruction strategy that generates a lean AGENTS.md hub with deep-dive detail files in a configurable directory (
.agents/by default), plus optional CLAUDE.md transclusion.Changes
InstructionStrategytype,parentArea,detailDir,claudeMdinAgentrcConfigwith validation--strategy <mode>and--claude-mdflags. CLI > config > default flatwriteInstructionFile()with traversal validation,writeNestedInstructions()orchestratordetectExistingInstructions()finds.agents/*.mddetail filesVerification