feat: add skillkit primer command for AI instruction generation#25
Conversation
New feature that analyzes codebases and generates AI instruction files for all 32 supported agents (inspired by pierceboggan/primer). ## New Module: packages/core/src/primer/ - types.ts: Zod schemas and TypeScript interfaces - analyzer.ts: Codebase analysis (languages, frameworks, conventions) - generator.ts: Agent-specific instruction file generation - index.ts: Barrel exports - __tests__/primer.test.ts: 15 comprehensive tests ## CLI Command: skillkit primer - --agent/-a: Generate for specific agents - --all-agents/-A: Generate for all 32 agents - --output/-o: Custom output directory - --dry-run/-n: Preview without writing - --analyze-only: Show analysis only - --verbose/-v: Detailed output - --json/-j: JSON output ## Features - Detects: languages, frameworks, package managers, libraries - Analyzes: project structure, code conventions, CI/CD, Docker - Generates: CLAUDE.md, .cursorrules, copilot-instructions.md, etc.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Caution Review failedThe pull request is closed. 📝 WalkthroughWalkthroughAdds a new Primer subsystem: static project analysis and per-agent AI instruction generation, a CLI Changes
Sequence Diagram(s)sequenceDiagram
participant CLI as PrimerCommand (CLI)
participant Analyzer as PrimerAnalyzer
participant Generator as PrimerGenerator
participant FS as File System
CLI->>Analyzer: analyzePrimer(projectPath)
activate Analyzer
Analyzer->>FS: scan files & configs
FS-->>Analyzer: metadata & artifacts
Analyzer-->>CLI: PrimerAnalysis
deactivate Analyzer
alt analyze-only
CLI->>CLI: print analysis
else generate
CLI->>Generator: generatePrimer(projectPath, agents, options)
activate Generator
Generator->>Generator: determine target agents
loop per agent
Generator->>Generator: build content sections (overview, stack, commands, conventions, structure, guidelines)
alt not dry-run
Generator->>FS: write instruction file(s)
FS-->>Generator: write results
end
end
Generator-->>CLI: PrimerResult (generated files, warnings, errors)
deactivate Generator
CLI->>CLI: print summary
end
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| if ('semi' in config) conventions.semicolons = config.semi; | ||
| if ('singleQuote' in config) conventions.quotes = config.singleQuote ? 'single' : 'double'; | ||
| if ('tabWidth' in config) { | ||
| conventions.indentation = config.useTabs ? 'tabs' : `spaces-${config.tabWidth}` as 'spaces-2' | 'spaces-4'; |
There was a problem hiding this comment.
🟡 Invalid indentation value created when tabWidth is not 2 or 4
When parsing Prettier configuration, the code constructs an indentation value using string interpolation spaces-${config.tabWidth}, but the Zod schema at types.ts:43 only allows 'tabs' | 'spaces-2' | 'spaces-4'.
Click to expand
Issue
If a project has a Prettier config with tabWidth: 3, tabWidth: 8, or any value other than 2 or 4, the code will create an invalid value like 'spaces-8' or 'spaces-3'.
Code at analyzer.ts:380-382:
if ('tabWidth' in config) {
conventions.indentation = config.useTabs ? 'tabs' : `spaces-${config.tabWidth}` as 'spaces-2' | 'spaces-4';
}Expected behavior
The code should validate that tabWidth is 2 or 4 before assigning, or map other values to the closest valid option.
Impact
This creates a type mismatch where the runtime value doesn't match the declared TypeScript type. While TypeScript won't catch this at compile time due to the as assertion, it could cause issues if the value is validated against the Zod schema or if downstream code expects only the valid enum values.
Recommendation: Validate tabWidth before assignment: conventions.indentation = config.useTabs ? 'tabs' : (config.tabWidth === 4 ? 'spaces-4' : 'spaces-2');
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@packages/core/src/primer/analyzer.ts`:
- Around line 1-3: relativePath is built using a hardcoded '/' replace and
directory counts check for '/' which breaks on Windows; update all occurrences
(the relativePath calculation and the directory-counting logic referenced around
lines 122-141 and 580-594) to use path.relative(...) to compute the path and use
path.sep (or split by path.sep) for any directory boundary checks/counts so
backslashes are normalized across OSes; replace manual string replace operations
that force '/' with these platform-safe utilities (refer to the variable name
relativePath and the directory-counting logic where split or indexOf('/') is
used).
In `@packages/core/src/primer/generator.ts`:
- Around line 60-92: The loop in generate() can overwrite outputs when multiple
agents produce the same filename (e.g., AGENTS.md); modify generate() to detect
duplicate output paths before writing by collecting each agent's intended output
path (use generateForAgent() to obtain the instruction.path or equivalent) and
checking against a set; on collision, either log a warning and skip writing for
the later agent (push a warning into warnings and an error into errors if
desired) or disambiguate the path (e.g., append agent name) before calling
writeInstruction(); ensure this check runs regardless of options.dryRun so
generated still reflects what would be produced and update
getTargetAgents()/generated/writeInstruction() usage accordingly.
In `@README.md`:
- Around line 316-326: Update the README's "AI Instruction Generation (Primer)"
examples to include usage examples for the missing CLI flags --output and --json
(alongside existing commands like "skillkit primer" and "skillkit primer
--all-agents"), e.g., show one example that writes generated primers to a
directory using --output <dir> and another that emits machine-readable output
using --json (optionally combined with --dry-run or --agent), ensuring the new
examples mention the exact flags (--output, --json) so users can discover them.
🧹 Nitpick comments (4)
packages/core/src/primer/types.ts (1)
93-95: Use the PackageManager enum in PrimerAnalysis
packageManagerscurrently accepts arbitrary strings even thoughPackageManageris defined. Using the enum keeps validation and downstream assumptions aligned.♻️ Suggested change
- packageManagers: z.array(z.string()).default([]), + packageManagers: z.array(PackageManager).default([]),packages/core/src/primer/analyzer.ts (1)
319-329: Detect monorepos before src‑based layoutIf
src/co-exists withpackages/orapps/, the current order labels the repo assrc-based, which can misclassify monorepos that don’t use workspaces. Consider checking monorepo markers first.♻️ Suggested change
- if (this.hasFile('src')) { - structure.type = 'src-based'; - structure.srcDir = 'src'; - } else if (this.hasFile('packages') || this.hasFile('apps')) { - structure.type = 'monorepo'; - } else if (this.hasFile('lib')) { + if (this.hasFile('packages') || this.hasFile('apps')) { + structure.type = 'monorepo'; + } else if (this.hasFile('src')) { + structure.type = 'src-based'; + structure.srcDir = 'src'; + } else if (this.hasFile('lib')) { structure.type = 'src-based'; structure.srcDir = 'lib'; } else {packages/core/src/primer/__tests__/primer.test.ts (1)
169-182: Add defensive check before accessing the first generated element.Line 176 accesses
result.generated[0]directly after asserting the operation succeeded. If the generator behavior changes and returns an empty array despitesuccess: true, this will throw an undefined access error rather than a clear test failure.🛡️ Proposed defensive assertion
expect(result.success).toBe(true); + expect(result.generated.length).toBeGreaterThan(0); const instruction = result.generated[0];packages/cli/src/commands/primer.ts (1)
103-117: Remove duplicateprojectPathparameter.
projectPathis passed both as the first positional argument togeneratePrimer()and again inside the options object at line 110. This is redundant and could cause confusion if the two values ever diverge.♻️ Proposed fix
const result = generatePrimer(projectPath, { - projectPath, agents, allAgents: this.allAgents, outputDir: this.output ? resolve(this.output) : undefined,
- Fix OS-agnostic path handling in analyzer using path.relative() and path.sep - Prevent output collisions when multiple agents produce same filename - Add defensive check in test before accessing generated[0] - Remove duplicate projectPath parameter in CLI primer command - Use PackageManager enum instead of z.string() for type safety - Detect monorepos before src-based layout to prevent misclassification - Document --output and --json flags in README examples
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@packages/core/src/primer/analyzer.ts`:
- Around line 234-240: The language detection block in Analyzer (method using
this.hasFile and pushing to languages) always sets source to 'pyproject.toml'
even when the match came from 'requirements.txt' or 'setup.py'; update the logic
in the analyzer.ts routine that builds the languages array (where hasFile is
called) to determine the actual matched filename and set source to that filename
(e.g., 'pyproject.toml', 'requirements.txt', or 'setup.py') instead of
hardcoding 'pyproject.toml' so the pushed object accurately reflects which file
triggered the Python detection.
In `@packages/core/src/primer/generator.ts`:
- Around line 174-181: getDefaultTemplate currently hardcodes format:
'markdown', which can produce files in the wrong format for agents whose
configurations in AGENT_CONFIG specify other formats (e.g., gemini-cli -> json,
cursor -> mdc); update getDefaultTemplate (in
packages/core/src/primer/generator.ts) to derive the default format from the
agent's entry in AGENT_CONFIG (use AgentType to look up
AGENT_CONFIG[agent].format or a sensible fallback like 'markdown') so the
returned AgentInstructionTemplate uses the agent-specific format rather than
always 'markdown'.
🧹 Nitpick comments (4)
packages/core/src/primer/generator.ts (1)
15-48: Consider deriving ALL_AGENTS from AGENT_CONFIG for consistency.The
ALL_AGENTSarray is hardcoded separately fromAGENT_CONFIG. If an agent is added toAGENT_CONFIGbut not here (or vice versa), they'll diverge silently.♻️ Suggested refactor to derive from AGENT_CONFIG
-const ALL_AGENTS: AgentType[] = [ - 'claude-code', - 'cursor', - // ... all 32 agents -]; +const ALL_AGENTS: AgentType[] = Object.keys(AGENT_CONFIG) as AgentType[];packages/core/src/primer/analyzer.ts (3)
177-205: Regex-based TOML parsing may be fragile for complex files.The regex patterns for
pyproject.tomlandCargo.tomlwork for simple cases but could miss values with inline comments, multiline strings, or complex quoting. Consider this a known limitation.For more robust parsing in the future, consider using a TOML parser library like
@iarna/tomlorsmol-toml. However, the current approach is acceptable for typical project files.
406-418: Questionable heuristic: path aliases implying camelCase.Setting
namingStyle: 'camelCase'based on the presence of@-prefixed path aliases seems unrelated. Path aliases don't indicate naming conventions.Consider removing this heuristic or replacing it with actual naming pattern detection from source files if needed in the future.
581-596: Unclear directory count estimation logic.The division by 3 at line 594 (
Math.floor(directories / 3)) is unexplained. Thedirectoriesvariable counts files with path separators, not actual unique directories. This metric may be confusing.Consider either documenting this heuristic or computing actual unique directory count:
private estimateCodebaseSize(): PrimerAnalysis['codebaseSize'] { let files = 0; - let directories = 0; + const directories = new Set<string>(); for (const file of this.files) { - if (file.includes(sep)) { - directories++; - } + const dir = file.split(sep).slice(0, -1).join(sep); + if (dir) directories.add(dir); files++; } return { files, - directories: Math.floor(directories / 3), + directories: directories.size, }; }
| private getDefaultTemplate(agent: AgentType, config: AgentDirectoryConfig): AgentInstructionTemplate { | ||
| return { | ||
| agent, | ||
| filename: config.configFile, | ||
| format: 'markdown', | ||
| sectionOrder: ['overview', 'stack', 'commands', 'conventions', 'structure', 'guidelines'], | ||
| }; | ||
| } |
There was a problem hiding this comment.
Default template format may mismatch agent's expected format.
getDefaultTemplate hardcodes format: 'markdown', but AGENT_CONFIG specifies different formats for various agents (e.g., gemini-cli uses json, cursor uses mdc). This could generate incorrectly formatted files for agents without explicit templates.
🛠️ Suggested fix to use agent's configured format
private getDefaultTemplate(agent: AgentType, config: AgentDirectoryConfig): AgentInstructionTemplate {
+ const formatMap: Record<AgentDirectoryConfig['configFormat'], AgentInstructionTemplate['format']> = {
+ 'xml': 'markdown',
+ 'markdown': 'markdown',
+ 'mdc': 'mdc',
+ 'json': 'json',
+ 'markdown-table': 'markdown',
+ };
return {
agent,
filename: config.configFile,
- format: 'markdown',
+ format: formatMap[config.configFormat] || 'markdown',
sectionOrder: ['overview', 'stack', 'commands', 'conventions', 'structure', 'guidelines'],
};
}🤖 Prompt for AI Agents
In `@packages/core/src/primer/generator.ts` around lines 174 - 181,
getDefaultTemplate currently hardcodes format: 'markdown', which can produce
files in the wrong format for agents whose configurations in AGENT_CONFIG
specify other formats (e.g., gemini-cli -> json, cursor -> mdc); update
getDefaultTemplate (in packages/core/src/primer/generator.ts) to derive the
default format from the agent's entry in AGENT_CONFIG (use AgentType to look up
AGENT_CONFIG[agent].format or a sensible fallback like 'markdown') so the
returned AgentInstructionTemplate uses the agent-specific format rather than
always 'markdown'.
- Fix Python detection to use correct source file (pyproject.toml, requirements.txt, or setup.py) - Escape regex special characters in glob pattern matching (e.g., *.module.css) - Derive ALL_AGENTS from AGENT_CONFIG to avoid divergence - Map agent config format to template format based on file extension
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@packages/core/src/primer/generator.ts`:
- Around line 161-188: generateContent currently hardcodes Markdown; update it
to respect template.format by passing the format into the section generation
flow and selecting format-specific renderers instead of always producing
Markdown. Concretely, change generateContent to read template.format (e.g.,
'md', 'mdc', 'json', 'xml'), pass that format into generateSection (and in turn
into generateOverviewSection, generateCapabilitiesSection, etc.), or dispatch to
format-specific helper functions that emit header/footer/customInstructions in
the correct syntax; ensure generateSection signature and all section generators
are updated to accept the format and produce the appropriate output so agents
(like the cursor agent targeting .mdc) get the correct format.
Refactored generateContent to properly respect the format field instead of always producing Markdown output. - Added FormatRenderer interface with format-specific implementations - Created renderers for markdown, mdc, json, xml formats - JSON format generates structured data via generateJsonContent() - MDC format includes YAML frontmatter via wrap() method - XML format properly escapes content with escapeXml() - Updated all section generators to accept and use the renderer
Summary
New feature that analyzes codebases and generates AI instruction files for all 32 supported agents, inspired by pierceboggan/primer.
New Module:
packages/core/src/primer/types.ts: Zod schemas and TypeScript interfacesanalyzer.ts: Codebase analysis (languages, frameworks, conventions)generator.ts: Agent-specific instruction file generation__tests__/primer.test.ts: 15 comprehensive testsCLI Command:
skillkit primerAnalysis Features
Generated Files
Creates agent-specific instruction files:
CLAUDE.mdfor Claude Code.cursorrulesfor Cursor.github/copilot-instructions.mdfor GitHub Copilot.gemini/settings.jsonfor Gemini CLITest plan
Summary by CodeRabbit
New Features
Documentation
Public API
Tests
✏️ Tip: You can customize this high-level summary in your review settings.