mirror of
https://github.com/alirezarezvani/ClaudeForge.git
synced 2026-07-03 02:13:15 -04:00
a45e6f5dbd
Turns ClaudeForge into an installable Claude Code plugin and adds the missing pieces for a clean lifecycle: hard line-cap enforcement, modular chaining via @path imports, a sync/cleanup command, and Explore-agent delegation for project discovery. - .claude-plugin/plugin.json: plugin manifest registering both skills, both commands, and the guardian agent (installable via /plugin marketplace add alirezarezvani/ClaudeForge && /plugin install claudeforge) - skill/validator.py: MAX_RECOMMENDED_LINES 300 -> 150 (warning at 120) - skill/template_selector.py: target_lines capped at 150 across all team sizes (solo 75 / small 100 / medium 125 / large 150) so any single CLAUDE.md fits within the cap; bigger projects spread content across modular sub-files - skill/analyzer.py: length thresholds, quality scoring, and recommendations rebased on the 150 cap (was 300/400) - skill/generator.py: modular root now emits @path imports next to the human-readable links; every sub-CLAUDE.md gets a back-link header pointing to ../CLAUDE.md (markdown + @import) for bidirectional chaining - command/sync-claude-md.md: new /sync-claude-md command that inventories every CLAUDE.md, prunes stale references, enforces the 150 cap by splitting into sub-files, and repairs the root <-> sub chain - command/enhance-claude-md.md: discovery phase now delegates the deep codebase scan to the Explore subagent to keep context lean - install.sh / install.ps1: each command in command/ installs as its own ~/.claude/commands/<name>.md (legacy bundle backed up on upgrade) - skill/SKILL.md, CLAUDE.md, README.md, CHANGELOG.md: docs updated for the plugin install path, sync command, and new line cap Verified via smoke test: validator constants, template targets, generator output line counts across 5 presets (all <= 150), context files with backlinks, @-import chain in modular root, idempotent merge_with_existing, validator status transitions at the new cap, analyzer quality differential, and plugin manifest JSON shape with all referenced paths existing on disk.
546 lines
22 KiB
Python
546 lines
22 KiB
Python
"""
|
|
CLAUDE.md Content Generator
|
|
|
|
Generates new CLAUDE.md files or enhances existing ones based on templates and analysis.
|
|
Supports modular architecture with context-specific files.
|
|
"""
|
|
|
|
from typing import Dict, List, Any, Optional
|
|
from template_selector import TemplateSelector
|
|
import re
|
|
|
|
|
|
class ContentGenerator:
|
|
"""Generates and enhances CLAUDE.md files based on project context."""
|
|
|
|
def __init__(self, project_context: Dict[str, Any]):
|
|
"""
|
|
Initialize content generator with project context.
|
|
|
|
Args:
|
|
project_context: Dictionary containing project type, tech_stack, team_size, etc.
|
|
"""
|
|
self.project_context = project_context
|
|
self.template_selector = TemplateSelector(project_context)
|
|
|
|
def generate_root_file(self) -> str:
|
|
"""
|
|
Generate root CLAUDE.md file (navigation hub).
|
|
|
|
Returns:
|
|
Complete CLAUDE.md content as string
|
|
"""
|
|
template = self.template_selector.select_template()
|
|
|
|
# Use template selector's customization
|
|
if template.get('modular_recommended'):
|
|
return self._generate_modular_root(template)
|
|
else:
|
|
return self._generate_standalone_file(template)
|
|
|
|
def _generate_modular_root(self, template: Dict[str, Any]) -> str:
|
|
"""Generate root file for modular architecture (navigation hub)."""
|
|
lines = []
|
|
|
|
# Title
|
|
lines.append("# CLAUDE.md")
|
|
lines.append("")
|
|
lines.append(f"This file provides top-level guidance for Claude Code when working with this {self.project_context.get('type', 'project')}.")
|
|
lines.append("")
|
|
|
|
# Quick Navigation
|
|
lines.append("## Quick Navigation")
|
|
lines.append("")
|
|
lines.extend(self._generate_navigation_section(template))
|
|
lines.append("")
|
|
|
|
# Core Principles (concise, 5-7 principles)
|
|
lines.append("## Core Principles")
|
|
lines.append("")
|
|
principles = self._generate_core_principles(template, max_count=5)
|
|
lines.extend(principles)
|
|
lines.append("")
|
|
|
|
# Behavioral Guidelines (Karpathy principles - applied to every project)
|
|
lines.append("## Behavioral Guidelines")
|
|
lines.append("")
|
|
lines.extend(self._generate_karpathy_guidelines())
|
|
lines.append("")
|
|
|
|
# Tech Stack (summary only)
|
|
if self.project_context.get('tech_stack'):
|
|
lines.append("## Tech Stack")
|
|
lines.append("")
|
|
lines.extend(self._generate_tech_stack_summary())
|
|
lines.append("")
|
|
|
|
# Key Commands/Shortcuts
|
|
lines.append("## Quick Reference")
|
|
lines.append("")
|
|
lines.extend(self._generate_quick_reference())
|
|
lines.append("")
|
|
|
|
# Footer
|
|
lines.append("---")
|
|
lines.append("")
|
|
lines.append("For detailed guidelines, see context-specific CLAUDE.md files in subdirectories.")
|
|
|
|
return '\n'.join(lines)
|
|
|
|
def _generate_standalone_file(self, template: Dict[str, Any]) -> str:
|
|
"""Generate standalone CLAUDE.md file (all-in-one)."""
|
|
return self.template_selector.customize_template(template)
|
|
|
|
def generate_context_file(self, context: str) -> str:
|
|
"""
|
|
Generate context-specific CLAUDE.md file (e.g., backend, frontend).
|
|
|
|
Args:
|
|
context: Context name ('backend', 'frontend', 'database', etc.)
|
|
|
|
Returns:
|
|
Context-specific CLAUDE.md content with a back-link to the root
|
|
CLAUDE.md so Claude can navigate back up the chain.
|
|
"""
|
|
generators = {
|
|
'backend': self._generate_backend_file,
|
|
'frontend': self._generate_frontend_file,
|
|
'database': self._generate_database_file,
|
|
'docs': self._generate_docs_file,
|
|
'.github': self._generate_github_file
|
|
}
|
|
|
|
generator = generators.get(context, self._generate_generic_context_file)
|
|
body = generator()
|
|
|
|
# Depth-aware back-link: most context dirs are one level deep, but
|
|
# ``.github`` may sit at the repo root next to the root CLAUDE.md.
|
|
rel_root = "../CLAUDE.md"
|
|
backlink = (
|
|
"> Parent context: see the root [CLAUDE.md]"
|
|
f"({rel_root}) for project-wide guidelines and behavioural rules.\n"
|
|
f"> Chained import: `@{rel_root}`\n\n"
|
|
)
|
|
return backlink + body
|
|
|
|
def _generate_backend_file(self) -> str:
|
|
"""Generate backend-specific CLAUDE.md."""
|
|
lines = []
|
|
lines.append("# Backend Development Guidelines")
|
|
lines.append("")
|
|
lines.append("This file provides guidance for backend development in this project.")
|
|
lines.append("")
|
|
|
|
# API Design
|
|
lines.append("## API Design")
|
|
lines.append("")
|
|
lines.append("- Use RESTful conventions for API endpoints")
|
|
lines.append("- Implement proper HTTP status codes (200, 201, 400, 404, 500)")
|
|
lines.append("- Version APIs when breaking changes are needed (/api/v1/, /api/v2/)")
|
|
lines.append("- Document all endpoints with OpenAPI/Swagger")
|
|
lines.append("")
|
|
|
|
# Database Guidelines
|
|
lines.append("## Database Operations")
|
|
lines.append("")
|
|
lines.append("- Use migrations for all schema changes")
|
|
lines.append("- Implement proper indexes for query performance")
|
|
lines.append("- Use transactions for multi-step operations")
|
|
lines.append("- Avoid N+1 queries - use joins or batch loading")
|
|
lines.append("")
|
|
|
|
# Error Handling
|
|
lines.append("## Error Handling")
|
|
lines.append("")
|
|
lines.append("- Implement global error handling middleware")
|
|
lines.append("- Log errors with context (request ID, user ID, timestamp)")
|
|
lines.append("- Return consistent error response format")
|
|
lines.append("- Never expose stack traces to clients in production")
|
|
lines.append("")
|
|
|
|
# Testing
|
|
lines.append("## Testing Requirements")
|
|
lines.append("")
|
|
lines.append("- Write unit tests for business logic")
|
|
lines.append("- Write integration tests for API endpoints")
|
|
lines.append("- Mock external services in tests")
|
|
lines.append("- Aim for 80%+ code coverage")
|
|
lines.append("")
|
|
|
|
return '\n'.join(lines)
|
|
|
|
def _generate_frontend_file(self) -> str:
|
|
"""Generate frontend-specific CLAUDE.md."""
|
|
lines = []
|
|
lines.append("# Frontend Development Guidelines")
|
|
lines.append("")
|
|
lines.append("This file provides guidance for frontend development in this project.")
|
|
lines.append("")
|
|
|
|
# Component Standards
|
|
lines.append("## Component Standards")
|
|
lines.append("")
|
|
tech_stack = [t.lower() for t in self.project_context.get('tech_stack', [])]
|
|
|
|
if 'react' in tech_stack:
|
|
lines.append("- Prefer functional components with hooks over class components")
|
|
lines.append("- Use TypeScript for type safety")
|
|
lines.append("- Keep components small and focused (< 200 lines)")
|
|
lines.append("- Extract reusable logic into custom hooks")
|
|
elif 'vue' in tech_stack:
|
|
lines.append("- Use Composition API for complex components")
|
|
lines.append("- Keep components small and focused (< 200 lines)")
|
|
lines.append("- Use TypeScript with Vue 3")
|
|
lines.append("- Extract reusable logic into composables")
|
|
else:
|
|
lines.append("- Keep components small and focused")
|
|
lines.append("- Extract reusable logic into utilities")
|
|
lines.append("- Use TypeScript for type safety")
|
|
lines.append("")
|
|
|
|
# State Management
|
|
lines.append("## State Management")
|
|
lines.append("")
|
|
lines.append("- Keep component state local when possible")
|
|
lines.append("- Use global state only for truly shared data")
|
|
lines.append("- Avoid prop drilling - use context/store for deep state")
|
|
lines.append("- Document state shape and update patterns")
|
|
lines.append("")
|
|
|
|
# Styling
|
|
lines.append("## Styling Guidelines")
|
|
lines.append("")
|
|
lines.append("- Use consistent naming conventions (BEM, CSS Modules, etc.)")
|
|
lines.append("- Avoid inline styles except for dynamic values")
|
|
lines.append("- Use design tokens for colors, spacing, typography")
|
|
lines.append("- Ensure responsive design for all breakpoints")
|
|
lines.append("")
|
|
|
|
# Performance
|
|
lines.append("## Performance Optimization")
|
|
lines.append("")
|
|
lines.append("- Lazy load routes and heavy components")
|
|
lines.append("- Optimize images (use WebP, lazy loading)")
|
|
lines.append("- Minimize bundle size - code split where possible")
|
|
lines.append("- Use memoization for expensive calculations")
|
|
lines.append("")
|
|
|
|
return '\n'.join(lines)
|
|
|
|
def _generate_database_file(self) -> str:
|
|
"""Generate database-specific CLAUDE.md."""
|
|
lines = []
|
|
lines.append("# Database Guidelines")
|
|
lines.append("")
|
|
lines.append("This file provides guidance for database operations and migrations.")
|
|
lines.append("")
|
|
|
|
# Schema Design
|
|
lines.append("## Schema Design")
|
|
lines.append("")
|
|
lines.append("- Use meaningful table and column names")
|
|
lines.append("- Always include created_at and updated_at timestamps")
|
|
lines.append("- Use proper foreign key constraints")
|
|
lines.append("- Add indexes for frequently queried columns")
|
|
lines.append("")
|
|
|
|
# Migrations
|
|
lines.append("## Migration Guidelines")
|
|
lines.append("")
|
|
lines.append("- Never edit existing migrations - create new ones")
|
|
lines.append("- Test migrations on copy of production data")
|
|
lines.append("- Include both up and down migrations")
|
|
lines.append("- Document breaking changes in migration comments")
|
|
lines.append("")
|
|
|
|
# Query Optimization
|
|
lines.append("## Query Optimization")
|
|
lines.append("")
|
|
lines.append("- Use EXPLAIN to analyze slow queries")
|
|
lines.append("- Avoid SELECT * - specify needed columns")
|
|
lines.append("- Use appropriate JOIN types")
|
|
lines.append("- Limit result sets with pagination")
|
|
lines.append("")
|
|
|
|
return '\n'.join(lines)
|
|
|
|
def _generate_docs_file(self) -> str:
|
|
"""Generate documentation-specific CLAUDE.md."""
|
|
lines = []
|
|
lines.append("# Documentation Guidelines")
|
|
lines.append("")
|
|
lines.append("This file provides guidance for project documentation.")
|
|
lines.append("")
|
|
|
|
lines.append("## Documentation Standards")
|
|
lines.append("")
|
|
lines.append("- Keep README.md updated with setup instructions")
|
|
lines.append("- Document all public APIs with examples")
|
|
lines.append("- Include architecture diagrams for complex systems")
|
|
lines.append("- Maintain changelog with semantic versioning")
|
|
lines.append("")
|
|
|
|
return '\n'.join(lines)
|
|
|
|
def _generate_github_file(self) -> str:
|
|
"""Generate .github-specific CLAUDE.md for CI/CD."""
|
|
lines = []
|
|
lines.append("# CI/CD Workflows")
|
|
lines.append("")
|
|
lines.append("This file provides guidance for GitHub Actions and CI/CD processes.")
|
|
lines.append("")
|
|
|
|
lines.append("## Workflow Guidelines")
|
|
lines.append("")
|
|
lines.append("- Run linting and tests on all pull requests")
|
|
lines.append("- Automate deployments to staging on main branch")
|
|
lines.append("- Require manual approval for production deployments")
|
|
lines.append("- Cache dependencies to speed up builds")
|
|
lines.append("")
|
|
|
|
return '\n'.join(lines)
|
|
|
|
def _generate_generic_context_file(self) -> str:
|
|
"""Generate generic context-specific file."""
|
|
return "# Context-Specific Guidelines\n\n[Add guidelines specific to this context]\n"
|
|
|
|
def generate_section(self, section_name: str) -> str:
|
|
"""
|
|
Generate a specific section for CLAUDE.md.
|
|
|
|
Args:
|
|
section_name: Name of section to generate
|
|
|
|
Returns:
|
|
Section content as string
|
|
"""
|
|
generators = {
|
|
'Core Principles': self._generate_core_principles_section,
|
|
'Tech Stack': self._generate_tech_stack_section,
|
|
'Workflow Instructions': self._generate_workflow_section,
|
|
'Testing Requirements': self._generate_testing_section,
|
|
'Error Handling': self._generate_error_handling_section,
|
|
'Documentation Standards': self._generate_documentation_section
|
|
}
|
|
|
|
generator = generators.get(section_name, self._generate_generic_section)
|
|
return generator(section_name)
|
|
|
|
def _generate_core_principles_section(self, section_name: str) -> str:
|
|
"""Generate Core Principles section."""
|
|
template = self.template_selector.select_template()
|
|
lines = [f"## {section_name}", ""]
|
|
lines.extend(self._generate_core_principles(template, max_count=7))
|
|
return '\n'.join(lines)
|
|
|
|
def _generate_tech_stack_section(self, section_name: str) -> str:
|
|
"""Generate Tech Stack section."""
|
|
lines = [f"## {section_name}", ""]
|
|
lines.extend(self._generate_tech_stack_summary())
|
|
return '\n'.join(lines)
|
|
|
|
def _generate_workflow_section(self, section_name: str) -> str:
|
|
"""Generate Workflow Instructions section."""
|
|
lines = [f"## {section_name}", ""]
|
|
|
|
workflows = self.project_context.get('workflows', [])
|
|
if workflows:
|
|
for i, workflow in enumerate(workflows, 1):
|
|
workflow_title = workflow.replace('_', ' ').title()
|
|
lines.append(f"{i}. **{workflow_title}**: [Add {workflow} workflow description]")
|
|
else:
|
|
lines.append("[Add workflow instructions specific to your project]")
|
|
|
|
return '\n'.join(lines)
|
|
|
|
def _generate_testing_section(self, section_name: str) -> str:
|
|
"""Generate Testing Requirements section."""
|
|
lines = [f"## {section_name}", ""]
|
|
lines.append("- Write tests before or alongside feature implementation")
|
|
lines.append("- Maintain minimum 80% code coverage")
|
|
lines.append("- Include unit, integration, and e2e tests")
|
|
lines.append("- Mock external dependencies in tests")
|
|
return '\n'.join(lines)
|
|
|
|
def _generate_error_handling_section(self, section_name: str) -> str:
|
|
"""Generate Error Handling section."""
|
|
lines = [f"## {section_name}", ""]
|
|
lines.append("- Implement comprehensive error handling from the start")
|
|
lines.append("- Log errors with context (user ID, request ID, timestamp)")
|
|
lines.append("- Provide helpful error messages to users")
|
|
lines.append("- Never expose sensitive information in error messages")
|
|
return '\n'.join(lines)
|
|
|
|
def _generate_documentation_section(self, section_name: str) -> str:
|
|
"""Generate Documentation Standards section."""
|
|
lines = [f"## {section_name}", ""]
|
|
lines.append("- Keep documentation in sync with code")
|
|
lines.append("- Document all public APIs and interfaces")
|
|
lines.append("- Include code examples in documentation")
|
|
lines.append("- Update README.md with setup and usage instructions")
|
|
return '\n'.join(lines)
|
|
|
|
def _generate_generic_section(self, section_name: str) -> str:
|
|
"""Generate generic section placeholder."""
|
|
return f"## {section_name}\n\n[Add {section_name.lower()} guidelines specific to your project]\n"
|
|
|
|
def merge_with_existing(self, existing_content: str, new_sections: List[str]) -> str:
|
|
"""
|
|
Merge new sections with existing CLAUDE.md content.
|
|
|
|
Args:
|
|
existing_content: Current CLAUDE.md content
|
|
new_sections: List of new sections to add
|
|
|
|
Returns:
|
|
Merged content as string
|
|
"""
|
|
lines = existing_content.split('\n')
|
|
existing_sections = self._extract_existing_sections(existing_content)
|
|
|
|
# Add new sections that don't already exist
|
|
for new_section in new_sections:
|
|
section_name = new_section.split('\n')[0].replace('## ', '')
|
|
if section_name not in existing_sections:
|
|
lines.append("")
|
|
lines.append(new_section)
|
|
|
|
# Always ensure the Karpathy behavioral guidelines section is present
|
|
if "Behavioral Guidelines" not in existing_sections:
|
|
lines.append("")
|
|
lines.append("## Behavioral Guidelines")
|
|
lines.append("")
|
|
lines.extend(self._generate_karpathy_guidelines())
|
|
|
|
return '\n'.join(lines)
|
|
|
|
def _extract_existing_sections(self, content: str) -> List[str]:
|
|
"""Extract section names from existing content."""
|
|
sections = []
|
|
for line in content.split('\n'):
|
|
if line.startswith('## '):
|
|
sections.append(line[3:].strip())
|
|
return sections
|
|
|
|
def _generate_navigation_section(self, template: Dict[str, Any]) -> List[str]:
|
|
"""Generate navigation section for modular architecture.
|
|
|
|
Emits both human-readable markdown links and Claude Code ``@`` imports
|
|
so the chained CLAUDE.md files are loaded automatically when the root
|
|
file is read.
|
|
"""
|
|
project_type = self.project_context.get('type')
|
|
targets: List[tuple] = [] # (label, relative_path)
|
|
|
|
if project_type == 'fullstack':
|
|
targets.append(("Backend Guidelines", "backend/CLAUDE.md"))
|
|
targets.append(("Frontend Guidelines", "frontend/CLAUDE.md"))
|
|
targets.append(("Database Operations", "database/CLAUDE.md"))
|
|
|
|
if 'cicd' in self.project_context.get('workflows', []):
|
|
targets.append(("CI/CD Workflows", ".github/CLAUDE.md"))
|
|
|
|
if not targets:
|
|
return ["- [Add links to context-specific CLAUDE.md files]"]
|
|
|
|
lines: List[str] = []
|
|
for label, path in targets:
|
|
lines.append(f"- [{label}]({path})")
|
|
lines.append("")
|
|
lines.append("Chained context (Claude Code auto-imports these):")
|
|
lines.append("")
|
|
for _, path in targets:
|
|
lines.append(f"@{path}")
|
|
|
|
return lines
|
|
|
|
def _generate_core_principles(self, template: Dict[str, Any], max_count: int = 7) -> List[str]:
|
|
"""Generate core principles list."""
|
|
principles = []
|
|
workflows = self.project_context.get('workflows', [])
|
|
|
|
# Add workflow-based principles
|
|
if 'tdd' in workflows:
|
|
principles.append("1. **Test-Driven Development**: Write tests before implementation")
|
|
|
|
# Add tech-specific principles
|
|
tech_custom = template.get('tech_customization', {})
|
|
for guideline in tech_custom.get('specific_guidelines', [])[:3]:
|
|
principle_num = len(principles) + 1
|
|
principles.append(f"{principle_num}. **{guideline.split(':')[0] if ':' in guideline else 'Guideline'}**: {guideline}")
|
|
|
|
# Add generic essential principles
|
|
generic = [
|
|
"**Code Quality**: Maintain high code quality with clear, readable implementations",
|
|
"**Documentation**: Keep documentation in sync with code changes",
|
|
"**Error Handling**: Implement comprehensive error handling from the start",
|
|
"**Performance**: Consider performance implications in implementation decisions",
|
|
"**Security**: Follow security best practices and avoid common vulnerabilities"
|
|
]
|
|
|
|
for principle in generic:
|
|
if len(principles) >= max_count:
|
|
break
|
|
principle_num = len(principles) + 1
|
|
principles.append(f"{principle_num}. {principle}")
|
|
|
|
return principles
|
|
|
|
def _generate_karpathy_guidelines(self) -> List[str]:
|
|
"""Emit the embedded Karpathy guidelines section.
|
|
|
|
Distilled summary applied to every generated CLAUDE.md. The full skill
|
|
text lives in the ``karpathy-guidelines`` skill installed alongside
|
|
ClaudeForge.
|
|
"""
|
|
return [
|
|
"Behavioral guardrails applied to every coding, review, and refactoring task.",
|
|
"Full skill: `~/.claude/skills/karpathy-guidelines/SKILL.md`.",
|
|
"",
|
|
"1. **Think before coding.** State load-bearing assumptions; if a request "
|
|
"has multiple reasonable interpretations, surface them instead of picking "
|
|
"silently. Stop and ask when something is genuinely unclear.",
|
|
"2. **Simplicity first.** Write the minimum code that solves the stated "
|
|
"problem. No speculative abstractions, no unrequested configuration, no "
|
|
"error handling for conditions that cannot occur. If the first draft is "
|
|
"much larger than necessary, rewrite before shipping.",
|
|
"3. **Surgical changes.** Touch only what the task requires. Do not "
|
|
"opportunistically reformat or refactor adjacent code, and match the "
|
|
"surrounding style. Every changed line should trace directly to the "
|
|
"user's request.",
|
|
"4. **Goal-driven execution.** Convert vague requests into verifiable "
|
|
"success criteria before coding (e.g. failing test first), and state a "
|
|
"step-by-step plan with per-step verification for multi-step work.",
|
|
]
|
|
|
|
def _generate_tech_stack_summary(self) -> List[str]:
|
|
"""Generate tech stack summary."""
|
|
lines = []
|
|
template = self.template_selector.select_template()
|
|
tech_custom = template.get('tech_customization', {})
|
|
|
|
if tech_custom.get('languages'):
|
|
lines.append(f"- **Languages**: {', '.join(tech_custom['languages'])}")
|
|
|
|
if tech_custom.get('frameworks'):
|
|
lines.append(f"- **Frameworks**: {', '.join(tech_custom['frameworks'])}")
|
|
|
|
if tech_custom.get('tools'):
|
|
lines.append(f"- **Tools**: {', '.join(tech_custom['tools'])}")
|
|
|
|
if not lines:
|
|
lines.append("- [Add your tech stack details here]")
|
|
|
|
return lines
|
|
|
|
def _generate_quick_reference(self) -> List[str]:
|
|
"""Generate quick reference commands."""
|
|
lines = []
|
|
lines.append("```bash")
|
|
lines.append("# Common development commands")
|
|
lines.append("npm test # Run tests")
|
|
lines.append("npm run lint # Run linter")
|
|
lines.append("npm run build # Build for production")
|
|
lines.append("```")
|
|
return lines
|