mirror of
https://github.com/alirezarezvani/ClaudeForge.git
synced 2026-07-03 02:13:15 -04:00
feat: ClaudeForge 2.1.0 — installable plugin with 150-line cap, forked audit skills, /sync --weekly, and AGENTS.md export (#26)
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
> Parent context: see the root [CLAUDE.md](../CLAUDE.md) for project-wide guidelines and behavioural rules.
|
||||
> Chained import: `@../CLAUDE.md`
|
||||
|
||||
# Skill Development
|
||||
|
||||
Guidelines for the `claudeforge-skill` Python modules and the `karpathy-guidelines` skill.
|
||||
|
||||
## Component Interaction Flow
|
||||
|
||||
```
|
||||
User Project
|
||||
↓
|
||||
/enhance-claude-md (Slash Command) → Explore subagent (deep scan)
|
||||
↓
|
||||
[Discovery] → [Analysis] → [Task]
|
||||
↓
|
||||
claude-md-guardian (Agent) OR Direct Skill Invocation
|
||||
↓
|
||||
claudeforge-skill (Python Modules)
|
||||
↓
|
||||
workflow.py → analyzer.py → validator.py → template_selector.py → generator.py
|
||||
↓
|
||||
CLAUDE.md ≤ 150 lines, chained via `@path` imports
|
||||
```
|
||||
|
||||
## Python Module Architecture
|
||||
|
||||
Five modules live under `skill/`:
|
||||
|
||||
- **`workflow.py`** — `InitializationWorkflow`: orchestrates interactive setup, detects project type / tech stack / team size / phase / workflows, returns a context dict.
|
||||
- **`analyzer.py`** — `CLAUDEMDAnalyzer`: analyses existing files; quality scoring (0–100) across length, completeness, formatting, specificity, modularity.
|
||||
- **`validator.py`** — `BestPracticesValidator`: checks file length (hard cap 150, warning at 120), required sections, formatting, anti-patterns.
|
||||
- **`template_selector.py`** — `TemplateSelector`: maps project type + team size to a template; all team-size targets are ≤ 150 lines.
|
||||
- **`generator.py`** — `ContentGenerator`: writes root + context files, emits `@path` chain imports, prepends sub-file back-links, idempotent `merge_with_existing`. Also exposes `generate_rules_file(name, description, paths, body)` for path-scoped `.claude/rules/*.md` files (loaded lazily by Claude when accessed files match the `paths:` globs) and prepends `@AGENTS.md`-style imports when `project_context['existing_instruction_files']` lists sibling instruction files.
|
||||
|
||||
## Required Output Sections
|
||||
|
||||
Every generated CLAUDE.md must contain:
|
||||
|
||||
- Project structure (ASCII tree, for projects that need it)
|
||||
- Setup & installation
|
||||
- Architecture (for non-trivial projects)
|
||||
- `## Behavioral Guidelines` (Karpathy summary — inserted automatically)
|
||||
- Cross-check against reference examples in `skill/examples/`
|
||||
|
||||
## Modifying Python Modules
|
||||
|
||||
1. Edit files in `skill/`.
|
||||
2. Run the smoke test (see `docs/CLAUDE.md` → Testing & Validation).
|
||||
3. Re-install for live testing: `./install.sh` (project-level scope).
|
||||
4. Test slash command: `/enhance-claude-md`.
|
||||
5. Validate output against `skill/examples/`.
|
||||
6. Update `CHANGELOG.md`.
|
||||
|
||||
## Adding Reference Templates
|
||||
|
||||
1. Add a new file under `skill/examples/`.
|
||||
2. Follow the native format (project structure, setup, architecture, tech guidelines).
|
||||
3. Update `skill/examples/README.md`.
|
||||
4. Teach `template_selector.py` how to detect the new template.
|
||||
5. Add a scenario to `skill/sample_input.json`.
|
||||
|
||||
## Quality Scoring (analyzer.py)
|
||||
|
||||
`calculate_quality_score()` breakdown:
|
||||
|
||||
- length_appropriateness: 25 pts (50–150 lines ideal; the 150-line hard cap is enforced here)
|
||||
- section_completeness: 25 pts (required sections present)
|
||||
- formatting_quality: 20 pts (markdown, heading hierarchy, code blocks)
|
||||
- content_specificity: 15 pts (project-specific, not generic)
|
||||
- modular_organization: 15 pts (chained sub-files when needed)
|
||||
|
||||
## Tech Stack Detection
|
||||
|
||||
`skill/workflow.py` → `_detect_tech_stack()` reads these signals:
|
||||
|
||||
- **Frontend** — React/Vue/Angular via `package.json`; Angular via `angular.json`; TypeScript via `tsconfig.json`.
|
||||
- **Backend** — Node (`package.json`), Python (`requirements.txt` / `pyproject.toml` / `setup.py`), Go (`go.mod`), Java (`pom.xml` / `build.gradle`), Rust (`Cargo.toml`).
|
||||
- **Database** — Postgres (`pg` / `psycopg2`), MongoDB (`mongoose` / `pymongo`), Redis (`redis` / `ioredis`).
|
||||
|
||||
Add new detectors there, not in the template selector.
|
||||
|
||||
## Karpathy Guidelines Skill
|
||||
|
||||
`skill/karpathy-guidelines/SKILL.md` is the standalone skill installed at `~/.claude/skills/karpathy-guidelines/`. Adapted with attribution from the MIT-licensed [forrestchang/andrej-karpathy-skills](https://github.com/forrestchang/andrej-karpathy-skills) repo. The four principles are inserted automatically into every generated CLAUDE.md via `template_selector._generate_karpathy_guidelines()` and `generator._generate_karpathy_guidelines()`. Do not strip the embedded section during enhancement.
|
||||
+28
-8
@@ -1,6 +1,25 @@
|
||||
---
|
||||
name: claude-md-enhancer
|
||||
description: Analyzes, generates, and enhances CLAUDE.md files for any project type using best practices, modular architecture support, and tech stack customization. Use when setting up new projects, improving existing CLAUDE.md files, or establishing AI-assisted development standards.
|
||||
model: haiku
|
||||
effort: medium
|
||||
paths:
|
||||
- "**/CLAUDE.md"
|
||||
- "**/CLAUDE.local.md"
|
||||
- "**/AGENTS.md"
|
||||
- "**/.cursorrules"
|
||||
- "**/.windsurfrules"
|
||||
- "**/.claude/rules/*.md"
|
||||
allowed-tools:
|
||||
- Read
|
||||
- Write
|
||||
- Edit
|
||||
- Glob
|
||||
- Grep
|
||||
- "Bash(ls:*)"
|
||||
- "Bash(find:*)"
|
||||
- "Bash(git:*)"
|
||||
- "Bash(wc:*)"
|
||||
permissions:
|
||||
allow:
|
||||
- Read
|
||||
@@ -8,9 +27,9 @@ permissions:
|
||||
- Edit
|
||||
- Glob
|
||||
- Grep
|
||||
- Bash(ls:*)
|
||||
- Bash(find:*)
|
||||
- Bash(git:*)
|
||||
- "Bash(ls:*)"
|
||||
- "Bash(find:*)"
|
||||
- "Bash(git:*)"
|
||||
---
|
||||
|
||||
# CLAUDE.md File Enhancer
|
||||
@@ -294,7 +313,7 @@ Analyzes existing CLAUDE.md files to identify structure, sections, and quality i
|
||||
Validates CLAUDE.md files against best practices and Anthropic guidelines.
|
||||
|
||||
**Key Functions**:
|
||||
- `validate_length()` - Check file length (warn if >300 lines)
|
||||
- `validate_length()` - Check file length (hard cap: 150 lines; warn from 120)
|
||||
- `validate_structure()` - Verify required sections present
|
||||
- `validate_formatting()` - Check markdown formatting quality
|
||||
- `validate_completeness()` - Ensure critical information included
|
||||
@@ -367,10 +386,11 @@ Before finalizing any CLAUDE.md generation:
|
||||
|
||||
## Template Categories
|
||||
|
||||
### By Size
|
||||
- **Minimal** (50 lines) - Solo developers, prototypes, hackathons
|
||||
- **Core** (100-150 lines) - Small teams, MVPs, standard projects
|
||||
- **Detailed** (200-300 lines) - Large teams, production systems, enterprise
|
||||
### By Size (single CLAUDE.md cap: 150 lines)
|
||||
- **Minimal** (≤ 75 lines) - Solo developers, prototypes, hackathons
|
||||
- **Core** (≤ 100 lines) - Small teams, MVPs, standard projects
|
||||
- **Detailed** (≤ 125 lines) - Medium teams, production systems
|
||||
- **Comprehensive** (≤ 150 lines + modular sub-files) - Large teams, enterprise; spread detail across chained sub-CLAUDE.md files instead of growing the root
|
||||
|
||||
### By Project Type
|
||||
- **Web App** - Frontend-focused (React, Vue, Angular)
|
||||
|
||||
+17
-10
@@ -165,17 +165,23 @@ class CLAUDEMDAnalyzer:
|
||||
issues = []
|
||||
|
||||
# Check file length
|
||||
if self.line_count > 400:
|
||||
if self.line_count > 250:
|
||||
issues.append({
|
||||
"type": "length_critical",
|
||||
"severity": "high",
|
||||
"message": f"File is too long ({self.line_count} lines). Recommended: split into modular files."
|
||||
"message": f"File is too long ({self.line_count} lines). Hard cap is 150; split into modular files."
|
||||
})
|
||||
elif self.line_count > 300:
|
||||
elif self.line_count > 150:
|
||||
issues.append({
|
||||
"type": "length_warning",
|
||||
"severity": "high",
|
||||
"message": f"File exceeds the 150-line cap ({self.line_count} lines). Split now."
|
||||
})
|
||||
elif self.line_count > 120:
|
||||
issues.append({
|
||||
"type": "length_warning",
|
||||
"severity": "medium",
|
||||
"message": f"File exceeds recommended 300 lines ({self.line_count} lines). Consider splitting."
|
||||
"message": f"File is approaching the 150-line cap ({self.line_count} lines)."
|
||||
})
|
||||
|
||||
# Check if file is too short
|
||||
@@ -238,12 +244,13 @@ class CLAUDEMDAnalyzer:
|
||||
"""
|
||||
score = 0
|
||||
|
||||
# Length appropriateness (25 points)
|
||||
if 50 <= self.line_count <= 300:
|
||||
# Length appropriateness (25 points). Hard cap is 150 lines; anything
|
||||
# above that loses points sharply because it indicates context bloat.
|
||||
if 50 <= self.line_count <= 150:
|
||||
score += 25
|
||||
elif 30 <= self.line_count < 50 or 300 < self.line_count <= 400:
|
||||
elif 30 <= self.line_count < 50 or 150 < self.line_count <= 200:
|
||||
score += 15
|
||||
elif self.line_count > 400:
|
||||
elif self.line_count > 200:
|
||||
score += 5
|
||||
else:
|
||||
score += 10
|
||||
@@ -329,9 +336,9 @@ class CLAUDEMDAnalyzer:
|
||||
recommendations.append(f"CRITICAL: {issue['message']}")
|
||||
|
||||
# Length recommendations
|
||||
if self.line_count > 300:
|
||||
if self.line_count > 150:
|
||||
recommendations.append(
|
||||
"Reduce root CLAUDE.md to <150 lines - move detailed guides to context-specific files"
|
||||
"Reduce this CLAUDE.md to <=150 lines (hard cap) - move detail to context-specific files and chain them via @path imports"
|
||||
)
|
||||
elif self.line_count < 30:
|
||||
recommendations.append(
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
---
|
||||
name: claude-md-dependency-rescan
|
||||
description: Re-detect this project's tech stack from package.json / requirements.txt / pyproject.toml / go.mod / Cargo.toml and diff it against the Tech Stack section of every CLAUDE.md. Read-only — returns added / removed / renamed dependencies, never edits.
|
||||
when_to_use: |
|
||||
Use when the user asks "is my Tech Stack section up to date?", "what deps changed?",
|
||||
"rescan my dependencies", after dependency upgrades, or as part of /sync-claude-md --weekly.
|
||||
argument-hint: "[manifest-path]"
|
||||
context: fork
|
||||
agent: Explore
|
||||
allowed-tools:
|
||||
- Read
|
||||
- Glob
|
||||
- Grep
|
||||
- "Bash(find:*)"
|
||||
- "Bash(cat:*)"
|
||||
disable-model-invocation: false
|
||||
---
|
||||
|
||||
# CLAUDE.md Dependency Rescan (forked, read-only)
|
||||
|
||||
Optional explicit manifest: `$ARGUMENTS` (default: auto-detect all five manifest types).
|
||||
|
||||
Run these steps in order. Do not modify any file.
|
||||
|
||||
1. **Detect manifests.** Look for `package.json`, `requirements.txt`, `pyproject.toml`, `go.mod`, `Cargo.toml` at the repo root and one level deep (workspaces/monorepos).
|
||||
2. **Extract declared dependencies** from each:
|
||||
- `package.json` → keys of `dependencies` and `devDependencies` (skip versions).
|
||||
- `requirements.txt` → first token of each non-comment line.
|
||||
- `pyproject.toml` → `[project.dependencies]` / `[tool.poetry.dependencies]` keys.
|
||||
- `go.mod` → module paths under `require (...)`.
|
||||
- `Cargo.toml` → keys under `[dependencies]` / `[dev-dependencies]`.
|
||||
3. **Inventory documented deps** in every `CLAUDE.md` (and `.claude/rules/*.md`): grep for the Tech Stack / Dependencies sections and the lists under them.
|
||||
4. **Compute three sets per file:**
|
||||
- `added`: in manifest but absent from this CLAUDE.md.
|
||||
- `removed`: documented in this CLAUDE.md but absent from manifest.
|
||||
- `renamed`: documented and present in manifest but spelled differently (`react-router` vs `react-router-dom`, `pg` vs `psycopg2`).
|
||||
5. **Return** in this exact shape:
|
||||
|
||||
```
|
||||
## Dependency Rescan
|
||||
|
||||
Manifests detected: <list>
|
||||
Total declared deps: <count>
|
||||
|
||||
### Per file
|
||||
#### <path-to-CLAUDE.md>
|
||||
- Added (in manifest, not documented): <list or "none">
|
||||
- Removed (documented, not in manifest): <list or "none">
|
||||
- Renamed / aliased: <list or "none">
|
||||
```
|
||||
|
||||
6. If every documented set matches its manifest, return exactly `## Dependency Rescan\n\nAll documented deps match manifests. <M> files inspected.`. Do not pad.
|
||||
|
||||
**Hard rule**: do not propose specific edits — just surface the diffs. `/sync-claude-md` decides whether to write them.
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
name: claude-md-drift-audit
|
||||
description: Audit every CLAUDE.md in this project for drift against the last week of git history. Flags sections that reference deleted files, renamed paths, or removed dependencies. Read-only — returns a punch list, never edits.
|
||||
when_to_use: |
|
||||
Use when the user asks "is my CLAUDE.md still accurate?", "audit my docs for staleness",
|
||||
"what changed in the last week?", or as part of /sync-claude-md --weekly.
|
||||
argument-hint: "[days=7]"
|
||||
context: fork
|
||||
agent: Explore
|
||||
allowed-tools:
|
||||
- Read
|
||||
- Glob
|
||||
- Grep
|
||||
- "Bash(git log:*)"
|
||||
- "Bash(git diff:*)"
|
||||
- "Bash(git status:*)"
|
||||
- "Bash(find:*)"
|
||||
disable-model-invocation: false
|
||||
---
|
||||
|
||||
# CLAUDE.md Drift Audit (forked, read-only)
|
||||
|
||||
Days window: `$ARGUMENTS` (default `7` if empty).
|
||||
|
||||
Perform these steps in order, then return a single punch-list summary. Do not modify any file.
|
||||
|
||||
1. **Inventory** every `CLAUDE.md` and `*.claude/rules/*.md` in the tree using `find . -name "CLAUDE.md" -type f -not -path "*/.git/*" -not -path "*/node_modules/*"`. List paths and line counts.
|
||||
2. **Collect change signal** for the window:
|
||||
- `git log --since="$ARGUMENTS days ago" --name-status --no-merges --diff-filter=DR` → deleted and renamed paths.
|
||||
- `git diff "@{$ARGUMENTS days ago}" --name-status -- package.json requirements.txt pyproject.toml go.mod Cargo.toml 2>/dev/null` → manifest deltas (removed/added deps).
|
||||
3. **Cross-reference** each CLAUDE.md against those signals using `grep` / `Read`:
|
||||
- Mark any line that names a deleted or renamed path.
|
||||
- Mark any line in a Tech Stack / Dependencies section that names a removed dep.
|
||||
- Mark any `@path/...` chain import or markdown link whose target was deleted.
|
||||
4. **Return** the punch list in this exact shape (markdown), nothing else:
|
||||
|
||||
```
|
||||
## Drift Audit (window: <N> days)
|
||||
|
||||
Total CLAUDE.md inspected: <count>
|
||||
Signals examined: <deleted_paths>, <renamed_paths>, <removed_deps>
|
||||
|
||||
### Findings
|
||||
- <path>:<line> — <one-sentence reason> — suggested action
|
||||
- ... (one bullet per drift; omit section if empty)
|
||||
|
||||
### Clean
|
||||
- <path> (lines unchanged, references valid)
|
||||
```
|
||||
|
||||
5. If no drift is found, return exactly `## Drift Audit\n\nNo drift in <N>-day window. <count> files inspected.`. Do not pad the output.
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
name: claude-md-link-check
|
||||
description: Verify every @path chain import and every markdown link inside every CLAUDE.md in this project resolves to an existing file. Read-only — returns broken links with file:line refs, never edits.
|
||||
when_to_use: |
|
||||
Use when the user asks "check my CLAUDE.md links", "are the @-imports still valid?",
|
||||
"find broken cross-references", or as part of /sync-claude-md --weekly.
|
||||
argument-hint: "[path-glob]"
|
||||
context: fork
|
||||
agent: Explore
|
||||
allowed-tools:
|
||||
- Read
|
||||
- Glob
|
||||
- Grep
|
||||
- "Bash(find:*)"
|
||||
- "Bash(test:*)"
|
||||
- "Bash(ls:*)"
|
||||
disable-model-invocation: false
|
||||
---
|
||||
|
||||
# CLAUDE.md Link Check (forked, read-only)
|
||||
|
||||
Optional path-glob: `$ARGUMENTS` (default `.` — entire tree).
|
||||
|
||||
Run these steps in order. Do not modify any file.
|
||||
|
||||
1. **Inventory.** `find <root> -name "CLAUDE.md" -type f -not -path "*/.git/*" -not -path "*/node_modules/*"`. Also include `.claude/rules/*.md`. Record paths.
|
||||
2. **Extract candidates** from each file:
|
||||
- **Chain imports** — lines matching `^@\S+`. The literal after `@` is a relative path.
|
||||
- **Markdown links** — `[text](target)` where `target` is not an HTTP(S) URL, not `mailto:`, not a bare anchor `#section`.
|
||||
3. **Resolve each candidate** relative to the file containing it (use `Read` on the parent file to confirm position, then `test -e <resolved-path>` or `Glob`).
|
||||
- For `@../CLAUDE.md` inside `skill/CLAUDE.md`, resolved path is `CLAUDE.md`.
|
||||
- For `[Backend](backend/CLAUDE.md)` inside the root, resolved path is `backend/CLAUDE.md`.
|
||||
4. **Return** the report in this exact shape:
|
||||
|
||||
```
|
||||
## Link Check
|
||||
|
||||
Files inspected: <count>
|
||||
References checked: <chain_imports> @-imports, <md_links> markdown links
|
||||
|
||||
### Broken
|
||||
- <file>:<line> — `<original-target>` → does not resolve (expected `<absolute-path>`)
|
||||
- ... (omit section if empty)
|
||||
|
||||
### Clean
|
||||
<count> references resolved.
|
||||
```
|
||||
|
||||
5. If everything resolves, return exactly `## Link Check\n\nAll <N> references resolved across <M> files.`. Do not pad.
|
||||
|
||||
**Hard rule**: never invent a fix. Report the broken target verbatim. Repair is the user's call (or `/sync-claude-md`'s).
|
||||
+114
-15
@@ -27,16 +27,48 @@ class ContentGenerator:
|
||||
"""
|
||||
Generate root CLAUDE.md file (navigation hub).
|
||||
|
||||
When the surrounding project already contains ``AGENTS.md``,
|
||||
``.cursorrules``, or ``.windsurfrules`` (passed via
|
||||
``project_context['existing_instruction_files']``), the generated root
|
||||
file prepends ``@`` imports for them so Claude inherits their content
|
||||
instead of duplicating it.
|
||||
|
||||
Returns:
|
||||
Complete CLAUDE.md content as string
|
||||
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)
|
||||
body = self._generate_modular_root(template)
|
||||
else:
|
||||
return self._generate_standalone_file(template)
|
||||
body = self._generate_standalone_file(template)
|
||||
|
||||
return self._prepend_existing_instruction_imports(body)
|
||||
|
||||
def _prepend_existing_instruction_imports(self, body: str) -> str:
|
||||
"""Insert ``@`` import lines for any AGENTS.md / cursor / windsurf files."""
|
||||
existing = self.project_context.get('existing_instruction_files') or []
|
||||
supported = ('AGENTS.md', '.cursorrules', '.windsurfrules')
|
||||
imports = [name for name in supported if name in existing]
|
||||
if not imports:
|
||||
return body
|
||||
|
||||
# Insert right after the intro paragraph (first blank line after the H1).
|
||||
lines = body.split('\n')
|
||||
out: List[str] = []
|
||||
inserted = False
|
||||
for i, line in enumerate(lines):
|
||||
out.append(line)
|
||||
if not inserted and i > 0 and line == '' and lines[i - 1].strip():
|
||||
out.append('## External Instructions')
|
||||
out.append('')
|
||||
out.append('Chained from sibling instruction files in this repo:')
|
||||
out.append('')
|
||||
for name in imports:
|
||||
out.append(f"@{name}")
|
||||
out.append('')
|
||||
inserted = True
|
||||
return '\n'.join(out) if inserted else body
|
||||
|
||||
def _generate_modular_root(self, template: Dict[str, Any]) -> str:
|
||||
"""Generate root file for modular architecture (navigation hub)."""
|
||||
@@ -99,7 +131,8 @@ class ContentGenerator:
|
||||
context: Context name ('backend', 'frontend', 'database', etc.)
|
||||
|
||||
Returns:
|
||||
Context-specific CLAUDE.md content
|
||||
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,
|
||||
@@ -110,7 +143,59 @@ class ContentGenerator:
|
||||
}
|
||||
|
||||
generator = generators.get(context, self._generate_generic_context_file)
|
||||
return generator()
|
||||
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_rules_file(
|
||||
self,
|
||||
name: str,
|
||||
description: str,
|
||||
paths: List[str],
|
||||
body: str,
|
||||
) -> str:
|
||||
"""Emit a path-scoped ``.claude/rules/*.md`` instruction file.
|
||||
|
||||
Anthropic loads these conditionally when Claude accesses files matching
|
||||
any of the ``paths:`` globs. Use this for sections that would otherwise
|
||||
bloat the root CLAUDE.md — e.g. backend-only standards that only matter
|
||||
when editing files under ``src/backend/**``.
|
||||
|
||||
Args:
|
||||
name: Skill-style identifier, kebab-case (e.g. ``backend-rules``).
|
||||
description: Single-sentence summary (used by Claude for matching).
|
||||
paths: List of glob patterns that trigger the load.
|
||||
body: Markdown content (excluding frontmatter and title).
|
||||
|
||||
Returns:
|
||||
Complete file content ready to write to ``.claude/rules/<name>.md``.
|
||||
Stays within the 150-line cap unless the caller passes a body that
|
||||
already exceeds it; the cap is enforced by the validator hook.
|
||||
"""
|
||||
if not paths:
|
||||
raise ValueError("paths must be a non-empty list of glob patterns")
|
||||
|
||||
lines: List[str] = ["---"]
|
||||
lines.append(f"name: {name}")
|
||||
lines.append(f"description: {description}")
|
||||
lines.append("paths:")
|
||||
for glob in paths:
|
||||
lines.append(f" - {glob}")
|
||||
lines.append("---")
|
||||
lines.append("")
|
||||
lines.append(f"# {name.replace('-', ' ').title()}")
|
||||
lines.append("")
|
||||
lines.append(body.strip())
|
||||
lines.append("")
|
||||
return "\n".join(lines)
|
||||
|
||||
def _generate_backend_file(self) -> str:
|
||||
"""Generate backend-specific CLAUDE.md."""
|
||||
@@ -412,22 +497,36 @@ class ContentGenerator:
|
||||
return sections
|
||||
|
||||
def _generate_navigation_section(self, template: Dict[str, Any]) -> List[str]:
|
||||
"""Generate navigation section for modular architecture."""
|
||||
"""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')
|
||||
links = []
|
||||
targets: List[tuple] = [] # (label, relative_path)
|
||||
|
||||
if project_type == 'fullstack':
|
||||
links.append("- [Backend Guidelines](backend/CLAUDE.md)")
|
||||
links.append("- [Frontend Guidelines](frontend/CLAUDE.md)")
|
||||
links.append("- [Database Operations](database/CLAUDE.md)")
|
||||
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', []):
|
||||
links.append("- [CI/CD Workflows](.github/CLAUDE.md)")
|
||||
targets.append(("CI/CD Workflows", ".github/CLAUDE.md"))
|
||||
|
||||
if not links:
|
||||
links.append("- [Add links to context-specific CLAUDE.md files]")
|
||||
if not targets:
|
||||
return ["- [Add links to context-specific CLAUDE.md files]"]
|
||||
|
||||
return links
|
||||
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."""
|
||||
|
||||
@@ -2,6 +2,34 @@
|
||||
name: karpathy-guidelines
|
||||
description: Behavioral guardrails for LLM-assisted coding. Use when writing, reviewing, or refactoring code in any project to avoid overcomplication, keep changes surgical, surface assumptions early, and execute against verifiable success criteria.
|
||||
license: MIT
|
||||
paths:
|
||||
- "**/*.py"
|
||||
- "**/*.ts"
|
||||
- "**/*.tsx"
|
||||
- "**/*.js"
|
||||
- "**/*.jsx"
|
||||
- "**/*.go"
|
||||
- "**/*.rs"
|
||||
- "**/*.java"
|
||||
- "**/*.kt"
|
||||
- "**/*.rb"
|
||||
- "**/*.php"
|
||||
- "**/*.swift"
|
||||
- "**/*.c"
|
||||
- "**/*.cc"
|
||||
- "**/*.cpp"
|
||||
- "**/*.h"
|
||||
- "**/*.hpp"
|
||||
- "**/*.cs"
|
||||
- "**/*.scala"
|
||||
- "**/*.sh"
|
||||
- "**/*.bash"
|
||||
- "**/*.zsh"
|
||||
- "**/*.sql"
|
||||
allowed-tools:
|
||||
- Read
|
||||
- Glob
|
||||
- Grep
|
||||
permissions:
|
||||
allow:
|
||||
- Read
|
||||
|
||||
@@ -78,7 +78,11 @@ class TemplateSelector:
|
||||
}
|
||||
}
|
||||
|
||||
# Team size templates
|
||||
# Team size templates. All targets stay <= MAX_LINES_PER_FILE (150) so any
|
||||
# single CLAUDE.md remains within the hard cap; larger projects spread
|
||||
# content across modular sub-files instead of growing the root file.
|
||||
MAX_LINES_PER_FILE = 150
|
||||
|
||||
TEAM_SIZE_TEMPLATES = {
|
||||
"solo": {
|
||||
"target_lines": 75,
|
||||
@@ -87,19 +91,19 @@ class TemplateSelector:
|
||||
"detail_level": "concise"
|
||||
},
|
||||
"small": {
|
||||
"target_lines": 125,
|
||||
"target_lines": 100,
|
||||
"complexity": "core",
|
||||
"focus": "Core guidelines, collaboration basics",
|
||||
"detail_level": "moderate"
|
||||
},
|
||||
"medium": {
|
||||
"target_lines": 200,
|
||||
"target_lines": 125,
|
||||
"complexity": "detailed",
|
||||
"focus": "Team coordination, process standardization",
|
||||
"detail_level": "comprehensive"
|
||||
},
|
||||
"large": {
|
||||
"target_lines": 275,
|
||||
"target_lines": 150,
|
||||
"complexity": "comprehensive",
|
||||
"focus": "Enterprise standards, governance",
|
||||
"detail_level": "extensive"
|
||||
|
||||
+30
-4
@@ -12,9 +12,10 @@ import re
|
||||
class BestPracticesValidator:
|
||||
"""Validates CLAUDE.md files against best practices and guidelines."""
|
||||
|
||||
# Maximum recommended line count
|
||||
MAX_RECOMMENDED_LINES = 300
|
||||
WARNING_THRESHOLD_LINES = 200
|
||||
# Hard cap: every CLAUDE.md (root or modular) must stay under this.
|
||||
# Modular split is required when content would exceed this cap.
|
||||
MAX_RECOMMENDED_LINES = 150
|
||||
WARNING_THRESHOLD_LINES = 120
|
||||
|
||||
# Minimum content requirements
|
||||
MIN_LINES = 20
|
||||
@@ -65,18 +66,24 @@ class BestPracticesValidator:
|
||||
}
|
||||
]
|
||||
|
||||
def __init__(self, content: str, project_context: Dict[str, Any] = None):
|
||||
def __init__(self, content: str, project_context: Dict[str, Any] = None, filename: str = None):
|
||||
"""
|
||||
Initialize validator with CLAUDE.md content.
|
||||
|
||||
Args:
|
||||
content: Full text content of CLAUDE.md file
|
||||
project_context: Optional project context for advanced validation
|
||||
filename: Optional path or basename. When the basename ends with
|
||||
``.local.md`` (e.g. ``CLAUDE.local.md``), the 150-line cap is
|
||||
relaxed because the file is a personal/gitignored override
|
||||
outside the chained team-shared tree.
|
||||
"""
|
||||
self.content = content
|
||||
self.lines = content.split('\n')
|
||||
self.line_count = len(self.lines)
|
||||
self.project_context = project_context or {}
|
||||
self.filename = filename or ""
|
||||
self.is_local_override = self.filename.endswith('.local.md')
|
||||
|
||||
def validate_all(self) -> Dict[str, Any]:
|
||||
"""
|
||||
@@ -111,6 +118,25 @@ class BestPracticesValidator:
|
||||
message = f"File length is appropriate ({self.line_count} lines)"
|
||||
severity = "info"
|
||||
|
||||
# CLAUDE.local.md (and any *.local.md sibling) is a personal,
|
||||
# gitignored override outside the chained team-shared tree. Skip the
|
||||
# 150-line cap — only flag underuse.
|
||||
if self.is_local_override:
|
||||
if self.line_count < self.MIN_LINES:
|
||||
status = "fail"
|
||||
message = f"Personal override is too short ({self.line_count} lines, minimum {self.MIN_LINES})"
|
||||
severity = "low"
|
||||
else:
|
||||
message = f"Personal override ({self.line_count} lines, cap waived)"
|
||||
return {
|
||||
"check": "file_length",
|
||||
"status": status,
|
||||
"message": message,
|
||||
"severity": severity,
|
||||
"actual_value": self.line_count,
|
||||
"expected_range": f"{self.MIN_LINES}+ lines (cap waived for *.local.md)",
|
||||
}
|
||||
|
||||
if self.line_count > self.MAX_RECOMMENDED_LINES:
|
||||
status = "fail"
|
||||
message = f"File exceeds maximum recommended length ({self.line_count} > {self.MAX_RECOMMENDED_LINES} lines)"
|
||||
|
||||
Reference in New Issue
Block a user