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:
Alireza Rezvani
2026-05-19 04:07:05 +02:00
committed by GitHub
parent ffff0fc4c3
commit 032c5e5a0f
35 changed files with 1740 additions and 629 deletions
+36
View File
@@ -0,0 +1,36 @@
{
"name": "claudeforge",
"description": "CLAUDE.md lifecycle toolkit: initialise, enhance, sync, and modularise CLAUDE.md files with a 150-line cap, automatic chaining, and Karpathy behavioural guardrails.",
"version": "2.1.0",
"author": {
"name": "Alireza Rezvani",
"url": "https://github.com/alirezarezvani"
},
"license": "MIT",
"homepage": "https://github.com/alirezarezvani/ClaudeForge",
"keywords": [
"claude-md",
"documentation",
"best-practices",
"modular",
"sync",
"karpathy",
"guidelines",
"context-management"
],
"skills": [
"./skill",
"./skill/karpathy-guidelines",
"./skill/claude-md-drift-audit",
"./skill/claude-md-link-check",
"./skill/claude-md-dependency-rescan"
],
"commands": [
"./command/enhance-claude-md.md",
"./command/sync-claude-md.md",
"./command/claude-to-agents.md"
],
"agents": [
"./agent/claude-md-guardian.md"
]
}
+8
View File
@@ -85,3 +85,11 @@ subagent-claude-md-guardian/
# Optional project files
PROJECT_SUMMARY.md
# ClaudeForge: personal / machine-local overrides outside the chained tree
CLAUDE.local.md
**/CLAUDE.local.md
.claude/settings.local.json
# ClaudeForge: per-developer hook overrides (e.g. disable validator locally)
hooks/hooks-config.local.json
+58 -4
View File
@@ -9,12 +9,66 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added (wave 5 — CLAUDE.md → AGENTS.md conversion for Codex / Gemini)
Cross-tool adoption: every project using ClaudeForge can now share its instructions with non-Claude tools (OpenAI Codex, Gemini Code Assist, anything honouring the AGENTS.md convention) without maintaining two files.
- **`/claude-to-agents`** slash command (`command/claude-to-agents.md`) with three modes:
- `--symlink` (default on macOS / Linux) — `AGENTS.md` becomes a symlink to `CLAUDE.md`. One source of truth; edits propagate instantly. Windows falls back to `--copy` automatically with a stderr notice.
- `--copy` — byte-for-byte snapshot. Use when the user wants to fork the instructions or when their VCS/build pipeline doesn't follow symlinks.
- `--inline-chain` — recursively walks every `@path/.../CLAUDE.md` import and writes a single flat AGENTS.md with all sub-file content inlined. **Recommended for Codex / Gemini in modular projects** because those tools don't auto-resolve `@`-imports.
- **`hooks/claude-to-agents.py`** — standalone, idempotent script. Backs up an existing `AGENTS.md` to `AGENTS.md.backup.<UTC-timestamp>` before overwrite (unless `--force`). Strips Claude-only scaffolding (backlink lines, `@`-import lines) from `--inline-chain` output. Cycle-safe (each file read at most once).
- Plugin manifest registers the new command. Both installers list it in their banner and uninstall instructions.
### Added (wave 4 — forked task-style audit skills)
Three new task-style skills under `skill/`, each using Anthropic's `context: fork` + `agent: Explore` so they run in an isolated subagent context (no caller chat history, ≤500-token summary back to the main session):
- **`claude-md-drift-audit`** (`skill/claude-md-drift-audit/SKILL.md`, 51 lines): walks the last N days of git history (default 7), cross-references every CLAUDE.md and `.claude/rules/*.md` against deleted paths / renamed paths / removed deps from that window, returns a punch list. Read-only.
- **`claude-md-link-check`** (`skill/claude-md-link-check/SKILL.md`, 51 lines): verifies every `@path` chain import and every relative markdown link inside every CLAUDE.md resolves to an existing file. Returns broken links with file:line refs. Read-only.
- **`claude-md-dependency-rescan`** (`skill/claude-md-dependency-rescan/SKILL.md`, 54 lines): re-detects the project's tech stack from `package.json` / `requirements.txt` / `pyproject.toml` / `go.mod` / `Cargo.toml`, diffs against every CLAUDE.md's Tech Stack section, returns added / removed / renamed lists per file. Read-only.
All three are standalone-invocable (`/claude-md-drift-audit`, etc.) and orchestrated by **`/sync-claude-md --weekly`**, which now opens with a Phase 0 that issues the three skills in parallel via the Skill tool before doing the normal sync work. Plugin manifest registers all five skills (the two existing + three new).
### Added (wave 3 — adoption hardening)
- **Command discovery metadata** (`command/enhance-claude-md.md`, `command/sync-claude-md.md`): both commands now declare `allowed-tools`, `disallowedTools` (blocks `WebFetch`/`WebSearch`), `argument-hint`, and `when_to_use` so Claude Code can auto-suggest and zero-prompt them.
- **Path-scoped Karpathy guidelines** (`skill/karpathy-guidelines/SKILL.md`): `paths:` glob on code-file extensions (`*.py`, `*.ts`, `*.go`, `*.rs`, etc.) so the guardrails load only when editing code, not when editing markdown or data.
- **Cheaper skill execution** (`skill/SKILL.md`): `model: haiku`, `effort: medium`, and `paths:` scoping the skill to CLAUDE.md / AGENTS.md / `.claude/rules/*.md` so validator + generator passes run cheaply without affecting the user-facing model.
- **`CLAUDE.local.md` personal tier**: `validator.BestPracticesValidator` now accepts `filename=` and waives the 150-line cap for any `*.local.md` file. `hooks/validate-claude-md.py` is exempt-suffix aware too. `.gitignore` excludes `CLAUDE.local.md`, `**/CLAUDE.local.md`, `.claude/settings.local.json`, and `hooks/hooks-config.local.json`.
- **Layered hook config** (`hooks/hooks-config.json` shared + `hooks/hooks-config.local.json` gitignored): `validate-claude-md.py` merges the two and honours `validateClaudeMd.enabled: false`, `maxLines`, `exemptFilenameSuffix`, and `exitCodeOnViolation`. Teams can opt out per developer without forking the shipped config.
- **`Stop` audit hook** (`hooks/audit-claude-md.py` + entry in `hooks/hooks.json`): prints a 1-line summary to stderr at session end — total CLAUDE.md tracked, count over the cap, count near it — so users see drift before the session's context is lost.
- **Fail-closed contract on guardian** (`agent/claude-md-guardian.md` Safety & Validation section): the guardian now states it invokes `claude-md-enhancer` exclusively through the Skill tool (never paraphrases SKILL.md content), aborts on missing validated output, never auto-commits, and respects the local hook config.
Patterns adapted (with attribution and in original prose) from the MIT-licensed [shanraisshan/claude-code-best-practice](https://github.com/shanraisshan/claude-code-best-practice).
### Fixed
- **Guardian agent hook frontmatter** (`agent/claude-md-guardian.md`): rewritten from the array-of-objects shape (`hooks: [{ event, commands }]`) to Anthropic's canonical keyed-object shape (`hooks: { EventName: [{ matcher, hooks: [{ type: "command", command }] }] }`). The previous shape did not match the documented schema, so the guardian's hooks did not fire. ([docs](https://code.claude.com/docs/en/hooks))
### Added
- **Karpathy Guidelines skill** (`skill/karpathy-guidelines/SKILL.md`): a behavioral-guardrail skill installed alongside ClaudeForge that applies to every coding, review, and refactoring task. Covers four principles — Think Before Coding, Simplicity First, Surgical Changes, Goal-Driven Execution — adapted with attribution from the MIT-licensed [forrestchang/andrej-karpathy-skills](https://github.com/forrestchang/andrej-karpathy-skills) repository.
- **Automatic embedding into every CLAUDE.md**: `skill/template_selector.py` and `skill/generator.py` now insert a `## Behavioral Guidelines` section into every generated and enhanced CLAUDE.md, so the principles ship with every project that runs `/enhance-claude-md`.
- **Installer support for the new skill**: `install.sh` and `install.ps1` now copy the skill to `~/.claude/skills/karpathy-guidelines/` (or the project-level equivalent) and include it in the uninstall instructions.
- **Slash command documentation**: `command/enhance-claude-md.md` documents the always-on Behavioral Guidelines section as a required part of the workflow.
- **Plugin-level hooks** (`hooks/hooks.json` + `hooks/validate-claude-md.py`): every `Edit`/`Write` to a `CLAUDE.md` and every `InstructionsLoaded` event (all five `load_reason` values — `session_start`, `nested_traversal`, `path_glob_match`, `include`, `compact`) runs `validate-claude-md.py`, which exits `2` with stderr feedback when the touched file exceeds the 150-line cap. Turns the cap from advisory into deterministic enforcement at load time and write time.
- **`generate_rules_file()` on `ContentGenerator`** (`skill/generator.py`): emits path-scoped `.claude/rules/*.md` instruction files with `name`, `description`, and `paths:` glob frontmatter. Claude loads these conditionally when accessing files that match the globs, so file-type-specific guidance (e.g. backend-only standards) no longer has to live in the root CLAUDE.md.
- **`AGENTS.md` / `.cursorrules` / `.windsurfrules` interop**: `command/enhance-claude-md.md` Phase 1 now detects these sibling instruction files, and `ContentGenerator.generate_root_file()` prepends an `## External Instructions` section with `@AGENTS.md`-style imports when `project_context['existing_instruction_files']` lists them. Repos already using other agent tooling can adopt ClaudeForge without losing their existing instructions.
### Added (earlier in this Unreleased window)
- **Claude Code plugin manifest** (`.claude-plugin/plugin.json`): ClaudeForge is now installable as a Claude Code plugin via `/plugin marketplace add alirezarezvani/ClaudeForge && /plugin install claudeforge`. Manifest registers all skills, commands, and the guardian agent in one bundle.
- **`/sync-claude-md` slash command** (`command/sync-claude-md.md`): walks every CLAUDE.md in the project, prunes stale references (removed dependencies, deleted paths, broken modular links), enforces the 150-line cap, and repairs the root ↔ sub chain. Designed to run after refactors, dependency changes, or before a release.
- **Karpathy Guidelines skill** (`skill/karpathy-guidelines/SKILL.md`): behavioural-guardrail skill applied to every coding, review, and refactoring task. Covers four principles — Think Before Coding, Simplicity First, Surgical Changes, Goal-Driven Execution — adapted with attribution from the MIT-licensed [forrestchang/andrej-karpathy-skills](https://github.com/forrestchang/andrej-karpathy-skills) repository.
- **Automatic embedding into every CLAUDE.md**: `skill/template_selector.py` and `skill/generator.py` insert a `## Behavioral Guidelines` section into every generated and enhanced CLAUDE.md.
- **Modular chaining via `@path` imports**: the modular root generator emits both human-readable markdown links and Claude Code `@path/to/CLAUDE.md` imports for every sub-CLAUDE.md. Sub-files now get a back-link header pointing to the root file so navigation is bidirectional.
- **Explore-agent delegation in `/enhance-claude-md`**: deep project scans are delegated to the Explore subagent to keep the calling session's context lean.
### Changed
- **Hard 150-line cap per CLAUDE.md**: `validator.MAX_RECOMMENDED_LINES` lowered from 300 to 150 (warning at 120). `template_selector.TEAM_SIZE_TEMPLATES` target lines lowered to fit (solo 75 / small 100 / medium 125 / large 150). `analyzer` length thresholds and quality scoring rebased on the new cap. Projects that need more content split it across chained sub-files instead of growing the root.
- **Installers register commands as top-level files**: `install.sh` and `install.ps1` now install each `.md` under `command/` as its own `~/.claude/commands/<name>.md` (registering as `/<name>`) rather than bundling the whole directory under one path. Legacy `~/.claude/commands/enhance-claude-md/` bundles are backed up automatically on upgrade.
### Verified
- Smoke tests: validator constants, all four team-size templates, generator output for solo/small/medium/large + library presets (all ≤ 150 lines), context files with back-links, `@`-import chain in modular root, idempotent `merge_with_existing`, validator status transitions (pass / warning / fail) at the new cap, analyzer quality score differential between compliant and bloated files, plugin manifest JSON shape and that every referenced path exists on disk.
---
+46 -493
View File
@@ -1,517 +1,70 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
---
Top-level guidance for Claude Code when working on this repository.
## Project Overview
**ClaudeForge** is a comprehensive toolkit for automated CLAUDE.md creation, enhancement, and maintenance for Claude Code projects. The repository consists of four integrated components:
**ClaudeForge** is a Claude Code plugin (manifest at `.claude-plugin/plugin.json`) and standalone toolkit for the CLAUDE.md lifecycle: initialise, enhance, sync, and modularise files with a hard **150-line cap**, automatic chaining via `@path` imports, and Karpathy behavioural guardrails. Works in any Claude Code or Claude.cowork project.
1. **Skill** (`claudeforge-skill`) - Core Python modules for analysis, generation, and validation
2. **Slash Command** (`/enhance-claude-md`) - Interactive multi-phase discovery workflow
3. **Guardian Agent** (`claude-md-guardian`) - Background maintenance agent
4. **Karpathy Guidelines Skill** (`karpathy-guidelines`) - Behavioral guardrails embedded into every generated CLAUDE.md and installed as a standalone skill, adapted with attribution from the MIT-licensed [forrestchang/andrej-karpathy-skills](https://github.com/forrestchang/andrej-karpathy-skills) repository
Five components ship in this repo:
---
1. **Skill** (`claudeforge-skill`, in `skill/`) — Python modules for analysis, generation, validation. Enforces the 150-line cap.
2. **Slash command** (`/enhance-claude-md`, in `command/`) — interactive init/enhance workflow. Delegates deep codebase scans to the Explore subagent.
3. **Slash command** (`/sync-claude-md`, in `command/`) — walks every CLAUDE.md, prunes stale references, enforces the 150-line cap, repairs the root ↔ sub chain.
4. **Guardian agent** (`claude-md-guardian`, in `agent/`) — background sync triggered by `SessionStart` / `PreToolUse` / `PostToolUse` hooks.
5. **Karpathy guidelines skill** (`karpathy-guidelines`, in `skill/karpathy-guidelines/`) — behavioural guardrails embedded into every generated CLAUDE.md. Adapted with attribution from the MIT-licensed [forrestchang/andrej-karpathy-skills](https://github.com/forrestchang/andrej-karpathy-skills) repo.
## What's New in v2.0.0
Current version: **2.1.0** — see `CHANGELOG.md`. v1 → v2 upgrade: `docs/MIGRATION_V2.md`.
**Claude Code v2.1.4+ Support:**
- **Lifecycle Hooks**: Guardian agent uses SessionStart, PreToolUse, PostToolUse hooks
- **Modern Permissions**: Updated to `permissions:` array syntax
- **Hot-Reload**: Skills auto-reload when modified (no restart needed)
- **Fork-Safe Mode**: Guardian runs independently with `fork_safe: true`
- **Auto-Migration**: Seamless upgrade from v1.x with automatic backups
## Quick Navigation
**Migration:** See `docs/MIGRATION_V2.md` for upgrading from v1.0.0.
- [Skill development](skill/CLAUDE.md)
- [Slash command development](command/CLAUDE.md)
- [Guardian agent development](agent/CLAUDE.md)
- [Installation, testing & release](docs/CLAUDE.md)
---
Chained context (Claude Code auto-imports these):
## Architecture
@skill/CLAUDE.md
@command/CLAUDE.md
@agent/CLAUDE.md
@docs/CLAUDE.md
### Component Interaction Flow
## Behavioral Guidelines
```
User Project
/enhance-claude-md (Slash Command)
[Phase 1: Discovery] → [Phase 2: Analysis] → [Phase 3: 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 Created/Updated with 100% Native Format
```
Behavioural guardrails applied to every coding, review, and refactoring task in this repo. Full skill: `~/.claude/skills/karpathy-guidelines/SKILL.md`.
### Python Module Architecture
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.
3. **Surgical changes.** Touch only what the task requires. Match 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 (failing test first), and state a step-by-step plan with per-step verification for multi-step work.
The skill consists of 5 core modules (~2,190 lines):
**workflow.py (432 lines)** - `InitializationWorkflow` class
- Orchestrates interactive initialization for new projects
- Methods: `check_claude_md_exists()`, `generate_exploration_prompt()`, `analyze_discoveries()`
- Detects: project type, tech stack, team size, development phase, workflows
- Returns: Project context dictionary for template selection
**analyzer.py (382 lines)** - `CLAUDEMDAnalyzer` class
- Analyzes existing CLAUDE.md files
- Methods: `analyze_file()`, `detect_sections()`, `calculate_quality_score()`, `generate_recommendations()`
- Quality scoring: 0-100 based on length (25pts), completeness (25pts), formatting (20pts), specificity (15pts), modularity (15pts)
- Returns: Analysis report with quality score and actionable recommendations
**validator.py (429 lines)** - `BestPracticesValidator` class
- Validates against Anthropic guidelines
- Methods: `validate_length()`, `validate_structure()`, `validate_formatting()`, `validate_completeness()`, `validate_all()`
- Checks: file length (20-300 lines), required sections, markdown formatting, anti-patterns
- Returns: Validation report with pass/fail status and detailed issues
**template_selector.py (467 lines)** - `TemplateSelector` class
- Selects appropriate template based on context
- Methods: `select_template()`, `customize_template()`, `recommend_modular_structure()`
- Logic: Maps project type + team size → template complexity
- Returns: Template configuration with target line count and modular recommendation
**generator.py (480 lines)** - `ContentGenerator` class
- Generates new or enhanced CLAUDE.md content
- Methods: `generate_root_file()`, `generate_context_file()`, `generate_section()`, `merge_with_existing()`
- Supports: Root files, context-specific files (backend/, frontend/, database/), individual sections
- Returns: Complete CLAUDE.md content with 100% native format compliance
### Critical Validation Rule
All generated CLAUDE.md files MUST include:
- Project structure (ASCII tree diagram)
- File structure explanations
- Setup & installation instructions
- Architecture section (for complex projects)
- Validation against `/update-claude-md` slash command format
- Cross-check against reference examples in `skill/examples/`
---
## Installation & Testing
### Test Installation Scripts
```bash
# macOS/Linux
./install.sh
# Choose option 1 (user-level) or 2 (project-level)
# Verify installation at ~/.claude/ or ./.claude/
# Windows
.\install.ps1
# Same options as above
# Verify components installed:
ls -la ~/.claude/skills/claudeforge-skill/
ls -la ~/.claude/commands/enhance-claude-md/
ls -la ~/.claude/agents/claude-md-guardian.md
```
### Directory Structure After Installation
```
~/.claude/ # User-level installation
├── skills/
│ └── claudeforge-skill/ # Copied from skill/
│ ├── SKILL.md
│ ├── analyzer.py
│ ├── validator.py
│ ├── generator.py
│ ├── template_selector.py
│ ├── workflow.py
│ └── examples/ # 7 reference templates
├── commands/
│ └── enhance-claude-md/ # Copied from command/
│ └── enhance-claude-md.md
└── agents/
└── claude-md-guardian.md # Copied from agent/
```
---
## Development Workflow
### Modifying Python Modules
When updating skill modules (analyzer.py, generator.py, etc.):
1. Edit files in `skill/` directory
2. Test changes by reinstalling: `./install.sh` (choose option 2 for project-level testing)
3. Test skill invocation in Claude Code: `/enhance-claude-md`
4. Validate output against reference examples in `skill/examples/`
5. Update `CHANGELOG.md` with changes
### Modifying Slash Command
When updating `/enhance-claude-md` command:
1. Edit `command/enhance-claude-md.md`
2. Key sections to modify:
- **Phase 1 (Discovery)**: Bash commands that check project state
- **Phase 2 (Analysis)**: Logic that determines initialize vs. enhance
- **Phase 3 (Task)**: Skill/agent invocation logic
3. Test by reinstalling command: `cp command/enhance-claude-md.md ~/.claude/commands/enhance-claude-md/`
4. Restart Claude Code and test: `/enhance-claude-md`
### Modifying Guardian Agent
When updating `claude-md-guardian` agent:
1. Edit `agent/claude-md-guardian.md`
2. Key YAML frontmatter fields:
- `permissions`: [Bash, Read, Write, Edit, Grep, Glob, Skill]
- `model`: Set to `haiku` for token efficiency
- `color`: Visual indicator (purple)
- `fork_safe`: Set to `true` for independent execution
- `hooks`: Array of lifecycle hooks (SessionStart, PreToolUse, PostToolUse)
3. Agent workflow phases:
- Phase 1: Assessment (check git changes)
- Phase 2: Analysis (determine scope)
- Phase 3: Update (invoke skill for targeted updates)
4. Test: `cp agent/claude-md-guardian.md ~/.claude/agents/`
**Example Agent Definition with v2.0.0 Syntax:**
```yaml
---
name: claude-md-guardian
permissions: [Bash, Read, Write, Edit, Grep, Glob, Skill]
model: haiku
color: purple
fork_safe: true
hooks:
- SessionStart
- PreToolUse
- PostToolUse
---
```
### Adding New Templates
To add a new reference template (e.g., Rust, mobile):
1. Create new template file in `skill/examples/`
2. Follow native format structure:
- Project structure diagram (ASCII tree)
- Setup & installation
- Architecture section
- Tech-specific guidelines
3. Update `skill/examples/README.md` with new template description
4. Update `template_selector.py` logic to detect when to use new template
5. Add test case in `skill/sample_input.json`
---
## Testing & Validation
### Manual Testing Checklist
**Test New Project Initialization:**
```bash
# 1. Create test project
mkdir test-project && cd test-project
git init
npm init -y # or create package.json
# 2. Run slash command
/enhance-claude-md
# 3. Verify Claude:
# - Explores repository
# - Detects TypeScript/Node project
# - Shows discoveries
# - Asks for confirmation
# - Creates CLAUDE.md with native format
```
**Test Existing Project Enhancement:**
```bash
# 1. Create basic CLAUDE.md
echo "# CLAUDE.md\n\n## Tech Stack\n- TypeScript" > CLAUDE.md
# 2. Run slash command
/enhance-claude-md
# 3. Verify Claude:
# - Analyzes existing file
# - Calculates quality score (0-100)
# - Identifies missing sections (Project Structure, Setup, etc.)
# - Asks to enhance
# - Adds missing native format sections
```
**Test Guardian Agent:**
```bash
# 1. Make significant changes
npm install react # Add new dependency
mkdir src/components # New directory
# 2. Start new Claude Code session (triggers SessionStart)
# 3. Verify agent:
# - Detects changes via git diff
# - Updates CLAUDE.md automatically
# - Reports: "Tech Stack: Added react", "Project Structure: Updated diagram"
```
### Quality Validation
All generated CLAUDE.md files should pass these checks:
```python
# Use validator.py
validator = BestPracticesValidator(content)
results = validator.validate_all()
# Expected passes:
# - File length: 20-300 lines (or modular if >300)
# - Structure: Required sections present
# - Formatting: Valid markdown, proper heading hierarchy
# - Completeness: Code examples, tech stack, workflows
# - Anti-patterns: No hardcoded secrets, no TODOs/placeholders
```
---
## File Organization
### Repository Structure
## Repository Layout (top level)
```
ClaudeForge/
├── skill/ # Python modules (core capability)
│ ├── analyzer.py # File analysis
│ ├── validator.py # Best practices validation
├── generator.py # Content generation
│ ├── template_selector.py # Template selection logic
│ ├── workflow.py # Interactive initialization
│ ├── SKILL.md # Skill definition (YAML frontmatter)
│ ├── sample_input.json # Test scenarios (6 examples)
│ ├── expected_output.json # Expected outputs
│ └── examples/ # 7 reference templates
├── command/ # Slash command definition
│ ├── enhance-claude-md.md # Multi-phase workflow
│ └── README.md
├── agent/ # Guardian agent definition
│ ├── claude-md-guardian.md # Background maintenance agent
│ └── README.md
├── docs/ # Documentation
│ ├── INSTALLATION.md
│ ├── QUICK_START.md
│ ├── ARCHITECTURE.md
│ ├── TROUBLESHOOTING.md
│ └── CONTRIBUTING.md
├── examples/ # Usage examples (markdown)
├── hooks/ # Quality hooks (pre-commit)
├── .github/ # GitHub templates & workflows
│ ├── workflows/validate.yml # CI/CD validation
│ ├── ISSUE_TEMPLATE/
│ ├── PULL_REQUEST_TEMPLATE.md
│ └── CODE_OF_CONDUCT.md
├── install.sh # macOS/Linux installer
├── install.ps1 # Windows installer
├── README.md # Project overview
├── CHANGELOG.md # Version history
├── LICENSE # MIT License
└── CLAUDE.md # This file
├── .claude-plugin/plugin.json # plugin manifest
├── skill/ # core Python modules + karpathy-guidelines/
├── command/ # /enhance-claude-md, /sync-claude-md
├── agent/ # claude-md-guardian
├── docs/ # operational docs (installation, testing, release)
├── examples/ # usage examples
├── hooks/ # quality hooks (pre-commit)
├── .github/ # CI workflows, issue/PR templates
├── install.sh / install.ps1 # installers
├── README.md / CHANGELOG.md / LICENSE
└── CLAUDE.md # this file
```
### Important: Dual Directory Structure
## Naming Reference
Note the duplication: `claude-md-enhancer/` (legacy) and `skill/` (current). When making changes:
- **Always edit `skill/`** - This is the active version used by installers
- `claude-md-enhancer/` is kept for reference but not actively maintained
- **Project / display name:** ClaudeForge
- **GitHub:** https://github.com/alirezarezvani/ClaudeForge
- **Skill name (frontmatter):** `claude-md-enhancer` (kept for backwards compatibility); installed as `claudeforge-skill/`
- **Slash commands:** `/enhance-claude-md`, `/sync-claude-md` (names fixed by file name)
- **Agent:** `claude-md-guardian`
- **Standalone skill:** `karpathy-guidelines`
---
## License
## Common Operations
### Update Reference Templates
```bash
# Edit template
vim skill/examples/python-api-CLAUDE.md
# Test template selection
# 1. Create test project matching template criteria
mkdir test-python-api && cd test-python-api
echo "fastapi" > requirements.txt
# 2. Run slash command and verify template is used
/enhance-claude-md
```
### Update Quality Scoring Logic
```bash
# Edit analyzer.py
vim skill/analyzer.py
# Update calculate_quality_score() method
# Current scoring breakdown:
# - length_appropriateness: 25 points (20-300 lines ideal)
# - section_completeness: 25 points (required sections present)
# - formatting_quality: 20 points (markdown, headings, code blocks)
# - content_specificity: 15 points (project-specific, not generic)
# - modular_organization: 15 points (context files if needed)
# Test scoring
python3 -c "
from skill.analyzer import CLAUDEMDAnalyzer
with open('test-CLAUDE.md') as f:
analyzer = CLAUDEMDAnalyzer(f.read())
report = analyzer.analyze_file()
print(f'Quality Score: {report[\"quality_score\"]}/100')
"
```
### Update Installer Scripts
```bash
# Edit installer
vim install.sh # or install.ps1
# Key sections:
# - Installation paths (user-level vs project-level)
# - Component copying (skill, command, agent)
# - Backup logic (existing installations)
# - Quality hooks installation (optional)
# Test installer
./install.sh
# Choose test option and verify all components copied correctly
```
---
## Integration Points
### Skill ↔ Slash Command
The slash command invokes the skill via:
```markdown
# In command/enhance-claude-md.md, Phase 3:
I can invoke the `claude-md-enhancer` skill directly to handle the appropriate workflow based on what I discovered above.
```
Claude Code recognizes the skill name `claude-md-enhancer` and calls Python modules.
### Skill ↔ Guardian Agent
The agent uses the skill as its core capability:
```yaml
# In agent/claude-md-guardian.md:
permissions: [Bash, Read, Write, Edit, Grep, Glob, Skill]
hooks:
- SessionStart # Detects project changes on session start
- PreToolUse # Validates before tool execution
- PostToolUse # Validates after CLAUDE.md updates
```
Agent invokes skill with: `Skill: claude-md-enhancer` in agent workflow.
**Example Hook Usage:**
```markdown
# When SessionStart hook triggers:
1. Check git diff for changes
2. If significant changes detected → invoke skill
3. Update CLAUDE.md automatically
# When PostToolUse hook triggers after Edit/Write to CLAUDE.md:
1. Validate updated content with validator.py
2. Report quality score
3. Suggest improvements if needed
```
### Agent ↔ Git
Agent detects changes via git commands:
```bash
git diff --name-status HEAD~10
git log --since="1 week ago" --oneline --no-merges
git diff HEAD~10 -- package.json requirements.txt
```
Triggers update when:
- 5+ files modified
- New dependencies added
- New directories created
- Manual invocation after milestone
---
## Tech Stack Detection Logic
The workflow and template selector detect tech stacks via:
**Frontend Detection:**
- React: `package.json` contains `"react"`
- Vue: `package.json` contains `"vue"`
- Angular: `angular.json` exists
- TypeScript: `tsconfig.json` exists
**Backend Detection:**
- Node.js: `package.json` exists
- Python: `requirements.txt`, `pyproject.toml`, `setup.py`
- Go: `go.mod` exists
- Java: `pom.xml`, `build.gradle`
- Rust: `Cargo.toml` exists
**Database Detection:**
- PostgreSQL: `package.json` or `requirements.txt` contains "pg" or "psycopg2"
- MongoDB: Contains "mongoose" or "pymongo"
- Redis: Contains "redis" or "ioredis"
Update detection logic in: `skill/workflow.py``_detect_tech_stack()` method
---
## Repository Naming
**Project Name:** ClaudeForge
**GitHub URL:** https://github.com/alirezarezvani/ClaudeForge
**Skill Name:** `claudeforge-skill` (installed as directory name)
**Slash Command:** `/enhance-claude-md` (fixed name, cannot be changed by user)
**Agent Name:** `claude-md-guardian` (file name)
When updating references:
- `skill/SKILL.md` → YAML frontmatter `name: claude-md-enhancer` (kept for compatibility)
- `README.md` → Use "ClaudeForge" as display name
- `install.sh` → Copies to `claudeforge-skill/` directory
- Internal documentation → Use "ClaudeForge" consistently
---
## Version Management
**Current Version:** 2.0.0 (see CHANGELOG.md)
**Versioning:** Semantic Versioning (MAJOR.MINOR.PATCH)
When releasing new version:
1. Update `CHANGELOG.md` with changes under new version header
2. Update version in `README.md` badge
3. Update version in `skill/SKILL.md` bottom section
4. Create git tag: `git tag -a v2.1.0 -m "Release v2.1.0"`
5. Push tag: `git push origin v2.1.0`
6. Create GitHub release with CHANGELOG excerpt
---
## License & Copyright
**License:** MIT License
**Copyright:** © 2025 Alireza Rezvani
All files should include appropriate copyright headers. The LICENSE file is authoritative.
MIT — © 2025 Alireza Rezvani. See `LICENSE`.
+63 -35
View File
@@ -12,16 +12,20 @@ ClaudeForge is a comprehensive toolkit that eliminates the tedious process of ma
---
## 🆕 New in v2.0 (Claude Code v2.1.4+ Support)
## 🆕 What's New
- **Lifecycle Hooks**: Guardian agent automatically checks for updates at session start using SessionStart hooks
- **Modern Permissions**: All components now use `permissions:` syntax for fine-grained control
- **Hot-Reload**: Skills automatically reload when modified (no restart needed)
- **Fork-Safe Mode**: Guardian runs independently with `fork_safe: true` without blocking operations
- **Version Detection**: Installers validate Claude Code version and ensure compatibility
- **Auto-Migration**: Seamless upgrade from v1.x with automatic backups
- **Installable Claude Code plugin** — manifest at `.claude-plugin/plugin.json`; install with `/plugin marketplace add alirezarezvani/ClaudeForge && /plugin install claudeforge`
- **Hard 150-line cap per CLAUDE.md** — enforced deterministically by `hooks/hooks.json` on `PostToolUse(Edit|Write)` *and* `InstructionsLoaded` (every `load_reason`); larger projects spread content across chained sub-files via `@path` imports
- **`/sync-claude-md`** — walks every CLAUDE.md, prunes stale references, splits when over the cap, repairs root ↔ sub chains
- **`/sync-claude-md --weekly`** — orchestrates three forked task-style skills in parallel: `claude-md-drift-audit`, `claude-md-link-check`, `claude-md-dependency-rescan`
- **Karpathy behavioural guidelines** auto-embedded in every generated CLAUDE.md and installed as a standalone `~/.claude/skills/karpathy-guidelines/` skill scoped to code-file globs
- **`AGENTS.md` / `.cursorrules` / `.windsurfrules` interop** — `/enhance-claude-md` detects sibling instruction files and chains them via `@`-imports instead of overwriting
- **`CLAUDE.local.md` personal tier** — per-developer overrides exempt from the cap, gitignored automatically
- **Layered hook config** — `hooks/hooks-config.json` (committed defaults) + `hooks/hooks-config.local.json` (gitignored) lets developers opt out per machine
- **Lifecycle hooks**: `SessionStart`, `PreToolUse`, `PostToolUse`, `InstructionsLoaded`, `Stop` (one-line drift summary at session end)
- **Guardian agent** runs `model: haiku` with a fail-closed contract (Skill-tool only, never auto-commits, aborts on missing validated output)
👉 **Upgrading from v1.x?** See [docs/MIGRATION_V2.md](docs/MIGRATION_V2.md) for migration guide.
👉 **Upgrading from v1.x?** See [docs/MIGRATION_V2.md](docs/MIGRATION_V2.md).
---
@@ -40,17 +44,30 @@ ClaudeForge is a comprehensive toolkit that eliminates the tedious process of ma
## 📦 What's Included
### 1. **Skill** (`claudeforge-skill`)
Core capability for CLAUDE.md analysis, generation, validation, and enhancement
### Skills
### 2. **Slash Command** (`/enhance-claude-md`)
Interactive interface with multi-phase discovery workflow
1. **`claudeforge-skill`** (`skill/SKILL.md`) — core analysis / validation / generation engine; runs on `model: haiku`. Scoped via `paths:` to `CLAUDE.md`, `CLAUDE.local.md`, `AGENTS.md`, `.cursorrules`, `.windsurfrules`, and `.claude/rules/*.md` so it auto-loads only when those files are touched.
2. **`karpathy-guidelines`** (`skill/karpathy-guidelines/SKILL.md`) — Think Before Coding, Simplicity First, Surgical Changes, Goal-Driven Execution. Embedded into every generated CLAUDE.md and installed as a standalone skill `paths:`-scoped to ~23 source-file extensions. Adapted with attribution from the MIT-licensed [forrestchang/andrej-karpathy-skills](https://github.com/forrestchang/andrej-karpathy-skills).
3. **`claude-md-drift-audit`** (`skill/claude-md-drift-audit/SKILL.md`, forked + `agent: Explore`) — walks the last N days of git history and flags every CLAUDE.md line that references deleted paths, renamed paths, or removed dependencies. Read-only. `/claude-md-drift-audit [days=7]`.
4. **`claude-md-link-check`** (`skill/claude-md-link-check/SKILL.md`, forked + `agent: Explore`) — verifies every `@path` chain import and every relative markdown link inside every CLAUDE.md resolves. Read-only. `/claude-md-link-check [path-glob]`.
5. **`claude-md-dependency-rescan`** (`skill/claude-md-dependency-rescan/SKILL.md`, forked + `agent: Explore`) — diffs declared dependencies (`package.json` / `requirements.txt` / `pyproject.toml` / `go.mod` / `Cargo.toml`) against the Tech Stack section of every CLAUDE.md. Read-only. `/claude-md-dependency-rescan [manifest]`.
### 3. **Guardian Agent** (`claude-md-guardian`)
Background agent for automatic CLAUDE.md maintenance and synchronization
### Slash commands
### 4. **Karpathy Guidelines Skill** (`karpathy-guidelines`)
Behavioral guardrails — Think Before Coding, Simplicity First, Surgical Changes, Goal-Driven Execution — installed as a standalone skill and automatically embedded into every CLAUDE.md generated or enhanced by `/enhance-claude-md`. Adapted with attribution from the MIT-licensed [forrestchang/andrej-karpathy-skills](https://github.com/forrestchang/andrej-karpathy-skills) repository, inspired by Andrej Karpathy's observations on common LLM coding failure modes.
- **`/enhance-claude-md`** (`command/enhance-claude-md.md`) — multi-phase init/enhance workflow with `argument-hint`, `when_to_use`, `allowed-tools`, and `disallowedTools` (blocks `WebFetch` / `WebSearch`). Delegates deep codebase scans to the Explore subagent.
- **`/sync-claude-md`** (`command/sync-claude-md.md`) — inventory → prune stale refs → enforce the 150-line cap → repair root ↔ sub chain. **New `--weekly` flag** orchestrates the three audit skills in parallel before doing sync work.
- **`/claude-to-agents`** (`command/claude-to-agents.md`) — convert the project's CLAUDE.md tree into an `AGENTS.md` for Codex / Gemini Code Assist / any tool honouring the AGENTS.md convention. Three modes: `--symlink` (one source of truth, default on macOS/Linux), `--copy` (snapshot), `--inline-chain` (flattens the `@path` chain into one self-contained file — recommended for modular projects since Codex/Gemini don't auto-resolve `@` imports). Backs up an existing AGENTS.md before overwrite.
### Agent
- **`claude-md-guardian`** (`agent/claude-md-guardian.md`) — background maintenance. Runs `model: haiku` with a fail-closed contract: Skill-tool only, aborts on missing validated output, never auto-commits, respects the local hook config.
### Hooks
- **`hooks/hooks.json`** — wires `PostToolUse(Write|Edit)`, `InstructionsLoaded` (all five `load_reason` values), and `Stop` events to scripts under `hooks/`.
- **`hooks/validate-claude-md.py`** — enforces the 150-line cap deterministically at load time *and* write time; exempts `*.local.md`; exits with stderr feedback on violation.
- **`hooks/audit-claude-md.py`** — `Stop` hook; one-line CLAUDE.md health summary printed at session end (total tracked / over cap / near cap).
- **`hooks/hooks-config.json`** + **`hooks/hooks-config.local.json`** — layered config; per-developer overrides without forking the shipped manifest.
---
@@ -58,6 +75,17 @@ Behavioral guardrails — Think Before Coding, Simplicity First, Surgical Change
### Installation
#### **Claude Code Plugin (recommended)**
ClaudeForge ships as a Claude Code plugin. From any Claude Code session:
```text
/plugin marketplace add alirezarezvani/ClaudeForge
/plugin install claudeforge
```
This installs every component (skills, slash commands, guardian agent) and registers `/enhance-claude-md` and `/sync-claude-md` for any project. Works the same at the user level (available everywhere) or scoped to a single project.
#### **macOS / Linux**
```bash
curl -fsSL https://raw.githubusercontent.com/alirezarezvani/ClaudeForge/main/install.sh | bash
@@ -203,18 +231,15 @@ See the [examples/](examples/) directory for:
### **Slash Command: /enhance-claude-md**
**Multi-Phase Workflow:**
1. **Discovery** - Checks for existing CLAUDE.md, examines project structure
2. **Analysis** - Determines appropriate action (initialize vs. enhance)
3. **Task** - Invokes skill or agent to execute workflow
**Multi-phase workflow** (Discovery → Analysis → Task). Discovery delegates the deep codebase walk to the Explore subagent so it doesn't bloat the calling session. Phase 1 also detects sibling `AGENTS.md` / `.cursorrules` / `.windsurfrules` and chains them via `@`-imports rather than overwriting. Phase 3 invokes `claudeforge-skill` via the Skill tool.
### **Slash Command: /sync-claude-md (with `--weekly`)**
Default mode: inventory every CLAUDE.md, prune stale references, enforce the 150-line cap by splitting into sub-files, repair the root ↔ sub chain. With `--weekly`, **Phase 0** issues the three forked audit skills (`claude-md-drift-audit`, `claude-md-link-check`, `claude-md-dependency-rescan`) in parallel via the Skill tool, aggregates their findings under `## Weekly Audit Summary`, then proceeds. Each forked skill runs in an isolated subagent context (`context: fork`, `agent: Explore`) so audit work doesn't bloat the calling session.
### **Agent: claude-md-guardian**
**Background Maintenance:**
- **Auto-Sync** - Updates CLAUDE.md based on detected changes
- **Smart Detection** - Only updates when significant changes occur
- **Token-Efficient** - Uses haiku model for routine updates
- **Milestone-Aware** - Triggers after feature completion, refactoring, etc.
Runs `model: haiku`, `fork_safe: true`. Hook frontmatter uses Anthropic's canonical keyed-object schema (events: `SessionStart`, `PreToolUse`, `PostToolUse`, `InstructionsLoaded`). **Fail-closed contract**: invokes `claudeforge-skill` exclusively through the Skill tool (never inlines SKILL.md), aborts on missing validated output, never auto-commits, respects `hooks/hooks-config.local.json`.
---
@@ -257,27 +282,30 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
## 🙏 Acknowledgments
- Built for the [Claude Code](https://claude.com/claude-code) community
- Inspired by best practices from Anthropic's official documentation
- Special thanks to all contributors and early adopters
- Built for the [Claude Code](https://claude.com/claude-code) community.
- The behavioural-guardrail skill adapts the four principles from the MIT-licensed [forrestchang/andrej-karpathy-skills](https://github.com/forrestchang/andrej-karpathy-skills) (inspired by Andrej Karpathy's commentary on LLM coding pitfalls). Original prose; attribution preserved in `skill/karpathy-guidelines/SKILL.md`.
- Several plugin conventions (layered hook config, `Stop` audit hook, command discovery metadata, `paths:` scoping on skills, fail-closed contracts) are adapted from the MIT-licensed [shanraisshan/claude-code-best-practice](https://github.com/shanraisshan/claude-code-best-practice). Patterns implemented in original code with attribution in `CHANGELOG.md`.
- Anthropic's [Claude Code documentation](https://code.claude.com/docs/en/memory) drove the load-event integrations (`InstructionsLoaded`, all five `load_reason` matchers) and the `context: fork` task-style skills.
---
## 🚦 Project Status
**Version:** 1.0.0
**Version:** 2.1.0 (see [CHANGELOG.md](CHANGELOG.md))
**Status:** ✅ Stable & Production-Ready
**Last Updated:** November 12, 2025
**Requires:** Claude Code 2.1.4+ for hooks/`InstructionsLoaded`/`paths:` features
---
## 📊 Quick Stats
- **7** reference CLAUDE.md templates included
- **100%** native Claude Code format compliance
- **5** Python modules
- **3** integrated components (skill, command, agent)
- **10+** usage examples and scenarios
- **5** skills (`claudeforge-skill`, `karpathy-guidelines`, plus three forked audit skills)
- **3** slash commands (`/enhance-claude-md`, `/sync-claude-md` with `--weekly`, `/claude-to-agents`)
- **1** agent (`claude-md-guardian`, fail-closed contract)
- **3** hook scripts wired across `PostToolUse`, `InstructionsLoaded`, `Stop`
- **5** Python modules under `skill/` (analyzer, validator, generator, template_selector, workflow)
- **7** reference CLAUDE.md templates under `skill/examples/`
- **150** — hard line cap per CLAUDE.md, enforced at load time *and* write time
---
+75
View File
@@ -0,0 +1,75 @@
> Parent context: see the root [CLAUDE.md](../CLAUDE.md) for project-wide guidelines and behavioural rules.
> Chained import: `@../CLAUDE.md`
# Guardian Agent Development
Guidelines for the `claude-md-guardian` background-maintenance agent.
## File
`agent/claude-md-guardian.md` — installs to `~/.claude/agents/claude-md-guardian.md`.
## Modifying the Agent
1. Edit `agent/claude-md-guardian.md`.
2. YAML frontmatter fields to preserve:
- `permissions: [Bash, Read, Write, Edit, Grep, Glob, Skill]`
- `model: haiku` — token efficiency for routine sync runs.
- `color: purple` — visual indicator in Claude Code UI.
- `fork_safe: true` — agent runs independently.
- `hooks: [SessionStart, PreToolUse, PostToolUse]`.
3. Workflow phases inside the agent:
- **Assessment** — read `git diff` / `git status` / changed-file counts.
- **Analysis** — decide if changes are significant enough to update CLAUDE.md.
- **Update** — invoke the skill for targeted section updates rather than full regeneration (~7080% token saving vs. rewrite).
4. Re-install for testing: `cp agent/claude-md-guardian.md ~/.claude/agents/`.
## v2.0.0+ Frontmatter Reference
Hooks use Anthropic's canonical keyed-object schema (event → array of `{ matcher, hooks: [{ type, command }] }`):
```yaml
hooks:
PostToolUse:
- matcher: "Write|Edit"
hooks:
- type: command
command: "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/validate-claude-md.py"
InstructionsLoaded:
- matcher: "session_start|nested_traversal|path_glob_match|include|compact"
hooks:
- type: command
command: "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/validate-claude-md.py"
```
The array-of-`{event, commands}` shape used in earlier versions did not match the documented schema and silently did not fire.
## Skill ↔ Agent Integration
The agent uses `claude-md-enhancer` (the skill's frontmatter name; installed as `claudeforge-skill/`) as its core capability. Invoke it with `Skill: claude-md-enhancer` inside the agent workflow.
Hook responsibilities:
- **SessionStart** — check `git diff`; if significant drift is detected, invoke the skill for an incremental update.
- **PreToolUse** — validate before a CLAUDE.md edit lands.
- **PostToolUse** — after `Edit`/`Write` to any CLAUDE.md, the plugin-level `hooks/hooks.json` runs `hooks/validate-claude-md.py`. The script exits `2` with stderr feedback when the file is over 150 lines; the guardian then proposes a `/sync-claude-md` run.
- **InstructionsLoaded** — same script fires on every `load_reason` (`session_start`, `nested_traversal`, `path_glob_match`, `include`, `compact`), so the cap is enforced deterministically at load time, not just at write time.
## Agent ↔ Git
The agent watches for change signals via:
```bash
git diff --name-status HEAD~10
git log --since="1 week ago" --oneline --no-merges
git diff HEAD~10 -- package.json requirements.txt pyproject.toml go.mod Cargo.toml
```
Triggers an update when any of these hold:
- 5+ files modified since the last sync.
- New dependencies added to a manifest file.
- New top-level directories created (potential new sub-CLAUDE.md candidates).
- Manual invocation after a milestone or release.
When the agent runs sync, it follows `command/sync-claude-md.md`: never commit, leave the diff for the user to review.
+30 -14
View File
@@ -16,18 +16,26 @@ field: documentation
expertise: intermediate
fork_safe: true
hooks:
- event: SessionStart
commands:
- echo "Guardian: Checking for CLAUDE.md updates..."
once: false
- event: PreToolUse
matcher: Write
commands:
- echo "Guardian: Validating CLAUDE.md changes..."
- event: PostToolUse
matcher: Write
commands:
- echo "Guardian: CLAUDE.md update complete"
SessionStart:
- matcher: ""
hooks:
- type: command
command: "echo 'Guardian: checking for CLAUDE.md drift on session start'"
PreToolUse:
- matcher: "Write|Edit"
hooks:
- type: command
command: "echo 'Guardian: validating CLAUDE.md change'"
PostToolUse:
- matcher: "Write|Edit"
hooks:
- type: command
command: "python3 ${CLAUDE_PLUGIN_ROOT:-${CLAUDE_PROJECT_DIR}}/hooks/validate-claude-md.py"
InstructionsLoaded:
- matcher: "session_start|nested_traversal|path_glob_match|include|compact"
hooks:
- type: command
command: "python3 ${CLAUDE_PLUGIN_ROOT:-${CLAUDE_PROJECT_DIR}}/hooks/validate-claude-md.py"
---
# CLAUDE.md Guardian Agent
@@ -233,8 +241,14 @@ The slash command can invoke me:
## Safety & Validation
**Critical Validation Rule**:
"Always validate your output against official native examples before declaring complete."
**Fail-closed contract** (non-negotiable):
- I invoke `claude-md-enhancer` exclusively through the **Skill tool**. I never read its `SKILL.md` body and act on a paraphrase of it — paraphrase drift is the most common silent-degradation mode for auto-CLAUDE.md tooling.
- If the skill returns no validated output (missing required sections, validator status ≠ `pass`, or any thrown exception), I **abort the run** and leave the existing CLAUDE.md tree untouched. Partial writes are worse than stale documentation.
- I never commit on my own. Every change lands in the working tree only; the user reviews `git diff` and chooses when to commit.
- I respect `hooks/hooks-config.local.json`. If a developer has disabled the validator locally, I treat the cap as advisory for that machine but still warn on the Stop hook.
**Critical Validation Rule**: validate every emitted file against the reference templates in `skill/examples/` and the canonical schema before declaring success.
**My validation checklist**:
- ✅ Project Structure diagram present
@@ -242,6 +256,8 @@ The slash command can invoke me:
- ✅ Architecture section reflects actual patterns
- ✅ Tech Stack lists all major dependencies
- ✅ Common Commands match package.json scripts
- ✅ Every emitted CLAUDE.md ≤ 150 lines (cap waived only for `*.local.md`)
- ✅ Every sub-CLAUDE.md back-links to root; root has matching `@`-imports
## Installation
+38
View File
@@ -0,0 +1,38 @@
> Parent context: see the root [CLAUDE.md](../CLAUDE.md) for project-wide guidelines and behavioural rules.
> Chained import: `@../CLAUDE.md`
# Slash Command Development
Guidelines for the `/enhance-claude-md` and `/sync-claude-md` slash commands.
## Files
- `command/enhance-claude-md.md` — interactive initialise / enhance workflow.
- `command/sync-claude-md.md` — walks every CLAUDE.md, prunes stale references, enforces the 150-line cap, repairs the root ↔ sub chain.
Both install as top-level `~/.claude/commands/<name>.md` so they register as `/enhance-claude-md` and `/sync-claude-md`. There is no `enhance-claude-md/` bundle directory anymore — legacy bundles are backed up automatically on upgrade.
## Modifying `/enhance-claude-md`
1. Edit `command/enhance-claude-md.md`.
2. Key phases:
- **Phase 1 (Discovery)** — bash inventory + Explore-subagent delegation for deep codebase walks. Keep the calling session's context lean.
- **Phase 2 (Analysis)** — branches initialise (no CLAUDE.md) vs. enhance (CLAUDE.md exists).
- **Phase 3 (Task)** — invokes the `claude-md-enhancer` skill or `claude-md-guardian` agent.
3. Always-on requirement: every generated/enhanced CLAUDE.md must include `## Behavioral Guidelines`. The skill inserts it automatically — do not strip it.
4. Re-install for testing: `./install.sh` (project-level) or copy the file manually to `~/.claude/commands/enhance-claude-md.md`.
5. Restart Claude Code (commands hot-reload, but restart guarantees a clean state) and test.
## Modifying `/sync-claude-md`
1. Edit `command/sync-claude-md.md`.
2. Phases: inventory → per-file audit → enforce 150-line cap (split into sub-files via `generator.generate_context_file()`) → re-chain root ↔ subs → cleanup report.
3. Sync should never commit on its own; leave the diff staged-but-uncommitted for the user.
## Skill ↔ Slash Command Integration
`command/enhance-claude-md.md` Phase 3 invokes the skill by name:
> I can invoke the `claude-md-enhancer` skill directly to handle the appropriate workflow based on what I discovered above.
Claude Code resolves `claude-md-enhancer` from the YAML frontmatter `name:` field in `skill/SKILL.md` (kept for backwards compatibility — the installed directory is `claudeforge-skill/`).
+61
View File
@@ -0,0 +1,61 @@
---
description: Convert the project's CLAUDE.md (and chained sub-files) into an AGENTS.md for Codex / Gemini Code Assist / other tools that follow the AGENTS.md convention. Three modes — symlink for one source of truth, copy for a snapshot, inline-chain for a self-contained flat file that doesn't depend on @-import resolution.
argument-hint: "[--symlink | --copy | --inline-chain] [--force]"
when_to_use: |
Use when the user asks "make an AGENTS.md", "support codex", "support gemini",
"convert CLAUDE.md", "share my instructions with non-Claude tools", or when
adopting ClaudeForge in a repo that already has cross-tool contributors.
allowed-tools:
- Read
- Write
- Glob
- "Bash(python3:*)"
- "Bash(ls:*)"
- "Bash(test:*)"
- "Bash(readlink:*)"
disallowedTools:
- WebFetch
- WebSearch
permissions:
allow:
- Read
- Write
- Glob
- "Bash(python3:*)"
- "Bash(ls:*)"
- "Bash(test:*)"
- "Bash(readlink:*)"
---
# /claude-to-agents — convert CLAUDE.md → AGENTS.md
Wraps `hooks/claude-to-agents.py` so non-Claude tools (OpenAI Codex, Gemini Code Assist, anything else honouring the `AGENTS.md` convention) can read the same instructions as Claude.
## Mode selection
Decide first by asking which guarantee the user wants:
- **`--symlink`** (default on macOS / Linux): `AGENTS.md` becomes a symlink to `CLAUDE.md`. One source of truth — edits to CLAUDE.md show up in AGENTS.md instantly. Codex/Gemini read it transparently. On Windows the script falls back to `--copy` and prints a notice.
- **`--copy`**: byte-for-byte snapshot. Use when the user wants to fork the instructions for non-Claude tooling (Codex/Gemini reading a different policy) or when their VCS / build pipeline doesn't follow symlinks.
- **`--inline-chain`**: walk every `@path/.../CLAUDE.md` chain import recursively and write a single flat AGENTS.md with all sub-file content inlined. **Recommended for Codex/Gemini in modular projects** — those tools don't resolve `@`-imports, so without inlining they'd only see the root file.
If the user is silent on mode, default to `--symlink` for simple projects and recommend `--inline-chain` for projects with > 1 CLAUDE.md (run `find . -name CLAUDE.md -type f -not -path '*/.git/*' -not -path '*/node_modules/*' | wc -l` first to decide).
## Execution
1. **Pre-flight.** `test -f CLAUDE.md` — if missing, tell the user `/enhance-claude-md` is the right command first.
2. **Run the script** with the chosen flags from the repo root:
```bash
python3 "${CLAUDE_PLUGIN_ROOT:-${CLAUDE_PROJECT_DIR:-.}}/hooks/claude-to-agents.py" --mode <mode>
```
3. **Report.** Echo whether AGENTS.md was created or backed up, its size, and which mode produced it.
4. **Verify** the result:
- For `--symlink`: `readlink AGENTS.md` should print `CLAUDE.md`.
- For `--copy`: `diff -q CLAUDE.md AGENTS.md` should return clean.
- For `--inline-chain`: AGENTS.md must contain content from every chained sub-file; the script strips backlinks and `@`-import lines automatically.
## Safety
- An existing `AGENTS.md` is renamed to `AGENTS.md.backup.<UTC-timestamp>` before overwrite. Pass `--force` to skip the backup (destructive).
- The script never writes outside the current directory tree.
- Read-only modes (`--symlink`) leave CLAUDE.md untouched.
+39 -9
View File
@@ -1,18 +1,34 @@
---
description: Initialize or enhance CLAUDE.md files using the claude-md-enhancer skill with interactive workflow and 100% native format compliance
description: Initialize or enhance a CLAUDE.md (and chained sub-CLAUDE.md files) for the current project using the claude-md-enhancer skill. Delegates deep codebase scans to the Explore subagent and stays within the 150-line cap.
argument-hint: "[--init | --enhance | <path-to-CLAUDE.md>]"
when_to_use: |
Use whenever a project has no CLAUDE.md, when an existing one is over 150 lines,
when an /init result needs to be hardened against context bloat, or when a repo
already uses AGENTS.md / .cursorrules / .windsurfrules and you want a Claude-
aware root that chains to them via @-imports instead of overwriting.
allowed-tools:
- Read
- Edit
- Write
- Glob
- Grep
- Skill
- "Bash(ls:*)"
- "Bash(find:*)"
- "Bash(git status:*)"
- "Bash(git diff:*)"
- "Bash(wc:*)"
disallowedTools:
- WebFetch
- WebSearch
permissions:
allow:
- Bash(ls:*)
- Bash(find:*)
- Bash(git status:*)
- "Bash(ls:*)"
- "Bash(find:*)"
- "Bash(git status:*)"
- Read
- Glob
- Skill
hooks:
- matcher: ""
once: true
commands:
- echo "Starting CLAUDE.md enhancement workflow"
---
# CLAUDE.md Enhancer Command
@@ -39,6 +55,20 @@ This command uses the `claude-md-enhancer` skill to initialize or enhance CLAUDE
!`ls -la`
### Check for sibling agent / rule files
If `AGENTS.md`, `.cursorrules`, or `.windsurfrules` exists, ClaudeForge will preserve it and chain it from the root CLAUDE.md via `@AGENTS.md` (or the equivalent) instead of overwriting. Detect them now:
!`for f in AGENTS.md .cursorrules .windsurfrules; do [ -f "$f" ] && echo "found: $f ($(wc -l < "$f") lines)" || echo "absent: $f"; done`
### Deep project scan via Explore agent
For non-trivial repositories, delegate the codebase walk to the **Explore** subagent so the discovery does not bloat this command's context window. Ask it a single, scoped question — for example:
> Walk this repository and report: project type (web_app / api / fullstack / cli / library / mobile / desktop), languages and frameworks detected, primary tech stack files (package.json, requirements.txt, pyproject.toml, go.mod, Cargo.toml), team-size indicators (number of contributors, CODEOWNERS), workflow indicators (.github/workflows, Dockerfile, CI configs), and any subdirectories that warrant their own CLAUDE.md (backend/, frontend/, database/, docs/, .github/). Return findings as a compact JSON object. Under 250 words.
Use the **general-purpose** subagent only for research that requires synthesising findings across multiple agents (e.g. comparing detected stack against template registry). Keep agent prompts self-contained and ask for short, structured reports.
---
## Phase 2: Analysis - Determine Action
+149
View File
@@ -0,0 +1,149 @@
---
description: Walk every CLAUDE.md in the project, prune stale references (removed deps, deleted paths, broken modular links), enforce the 150-line cap by splitting into sub-files, and repair the root ↔ subdirectory chain (markdown links + @path imports).
argument-hint: "[--weekly | --dry-run | --paths-only | <directory>]"
when_to_use: |
Run after refactors, dependency changes, deleted directories, or when any single
CLAUDE.md is near the 150-line cap. Use --weekly for a periodic audit pass that
parallel-invokes the drift-audit, link-check, and dependency-rescan forked skills
before doing the normal sync work. Also run before cutting a release so the
documentation tag-snapshot is truthful.
allowed-tools:
- Read
- Edit
- Write
- Glob
- Grep
- Skill
- "Bash(ls:*)"
- "Bash(find:*)"
- "Bash(git status:*)"
- "Bash(git diff:*)"
- "Bash(wc:*)"
- "Bash(grep:*)"
- "Bash(cat:*)"
- "Bash(test:*)"
disallowedTools:
- WebFetch
- WebSearch
permissions:
allow:
- "Bash(ls:*)"
- "Bash(find:*)"
- "Bash(git status:*)"
- "Bash(git diff:*)"
- "Bash(wc:*)"
- "Bash(grep:*)"
- "Bash(cat:*)"
- "Bash(test:*)"
- Read
- Edit
- Write
- Glob
- Grep
- Skill
---
# /sync-claude-md — CLAUDE.md Sync & Cleanup
This command keeps every CLAUDE.md in the project current, lean, and chained. Apply the Karpathy behavioural guidelines (`~/.claude/skills/karpathy-guidelines/SKILL.md`) while running it: state assumptions, keep changes surgical, define verification per step.
---
## Phase 0: Weekly Audit (only when `--weekly` is passed)
When the user invokes `/sync-claude-md --weekly`, run the three audit skills in parallel via the **Skill tool** before touching any file. Each is forked (`context: fork`, `agent: Explore`) so its work happens in an isolated context and only the summary returns:
1. `Skill(claude-md-drift-audit)` — references against last 7 days of git history.
2. `Skill(claude-md-link-check)``@path` imports and markdown links resolve.
3. `Skill(claude-md-dependency-rescan)` — Tech Stack sections vs. manifest files.
Issue all three in a single message so they execute concurrently. Wait for all three to return, then aggregate their findings into one report at the top of this run — `## Weekly Audit Summary` with one subsection per skill. If any audit returns findings, proceed to Phase 1 with those findings in mind so the sync work resolves them. If all three are clean, skip to Phase 4 (chain repair) — no edits required.
When `--weekly` is not passed, skip this phase entirely and start at Phase 1.
---
## Phase 1: Inventory
Discover every CLAUDE.md in the project (skipping vendor directories) and report sizes.
!`find . -name "CLAUDE.md" -type f -not -path "./node_modules/*" -not -path "./.git/*" -not -path "./vendor/*" -not -path "./dist/*" -not -path "./build/*" -print -exec wc -l {} \;`
Then capture the project signal that drives staleness checks:
!`ls -la package.json requirements.txt pyproject.toml go.mod Cargo.toml 2>/dev/null || true`
!`git status --short 2>/dev/null || echo "Not a git repository"`
!`git diff --name-status HEAD~10 -- . 2>/dev/null | head -50 || true`
---
## Phase 2: Per-File Audit
For each CLAUDE.md found, run the `claude-md-enhancer` skill's analyzer to compute:
- Current line count (hard cap: **150 lines**)
- Sections present and their freshness
- Anti-patterns (TODO/placeholder text, hardcoded secrets, generic content)
- References to files, directories, packages, or scripts that may be stale
Stale references to flag and remove unless the user objects:
1. **Dependency references** — packages mentioned in CLAUDE.md but absent from `package.json` / `requirements.txt` / `pyproject.toml` / `go.mod` / `Cargo.toml`.
2. **File / directory references** — paths in the project structure section that no longer exist on disk.
3. **Script references** — commands in Quick Reference / Common Operations that point to removed npm scripts or Makefile targets.
4. **Modular link targets**`[Backend Guidelines](backend/CLAUDE.md)` or `@backend/CLAUDE.md` imports where the target file no longer exists.
5. **Version drift** — version numbers / "What's New in vX.Y" sections referencing releases older than what `CHANGELOG.md` shows as current.
For each finding, show the offending line(s) with file:line references before editing.
---
## Phase 3: Enforce the 150-Line Cap
Any CLAUDE.md exceeding 150 lines must be split. Prefer this order:
1. **Move detail to existing sub-files.** If `backend/CLAUDE.md` exists, push backend-specific content there.
2. **Create a new sub-file** in the appropriate directory (e.g. `database/CLAUDE.md`) using `claude-md-enhancer.generate_context_file()`. The generator automatically prepends a back-link to the root.
3. **Update the root file's navigation** — both the human-readable bullets and the `@path/to/CLAUDE.md` chain imports — using `claude-md-enhancer`.
After splitting, re-validate every modified file with `BestPracticesValidator` and confirm line count ≤ 150.
---
## Phase 4: Re-chain Root ↔ Sub Files
Verify the bidirectional chain:
- Root CLAUDE.md must contain a `Quick Navigation` block listing every existing sub-CLAUDE.md, plus a `@<relative-path>` import line for each.
- Every sub-CLAUDE.md must contain a back-link at the top pointing to `../CLAUDE.md` (or the correct relative path) with both a markdown link and a `@../CLAUDE.md` import.
Repair any missing or broken chain links. Remove chain entries for sub-files that have been deleted.
---
## Phase 5: Cleanup & Report
After edits, regenerate validator output for each file and show:
- Files modified
- Lines removed (stale content)
- Sections added / split / removed
- Final line count per file (must all be ≤ 150)
- Remaining warnings the user should review manually
Do not commit. Leave the diff staged-but-uncommitted so the user can review with `git diff` and choose when to commit.
---
## When to Run
- After completing a feature, major refactor, or dependency change.
- When `claude-md-guardian` flags drift on session start.
- Whenever any single CLAUDE.md grows past ~120 lines (warning threshold).
- Before cutting a release — keeps documentation truthful at the tag boundary.
## Companion Tools
- `/enhance-claude-md` — initialise or upgrade a CLAUDE.md when one is missing or thin.
- `claude-md-guardian` agent — runs sync automatically on session start when changes are detected.
- `karpathy-guidelines` skill — behavioural rules applied to every edit this command makes.
+7 -6
View File
@@ -211,9 +211,10 @@ def calculate_quality_score(self) → int:
**Validation Categories:**
1. **Length Validation**
- Recommended: 20-300 lines
- Warning: 300-400 lines (suggest modular)
- Error: < 20 or > 400 lines
- Recommended: 20120 lines (sweet spot)
- Warning: 120150 lines (approaching cap)
- **Hard cap: 150 lines** — enforced deterministically by `hooks/validate-claude-md.py` on `PostToolUse(Edit|Write)` *and* `InstructionsLoaded`. Files over the cap must be split into chained sub-CLAUDE.md files.
- Exempt: any file whose basename ends in `.local.md` (personal-tier override).
2. **Structure Validation**
- Required sections: Core Principles, Tech Stack, Workflow
@@ -432,9 +433,9 @@ Triggers update if:
### File Size Limits
- Single file: Max 400 lines (prefer 300)
- Modular files: Each 150-300 lines
- Total project: Unlimited with modular
- Every CLAUDE.md: hard cap 150 lines (no exceptions outside `*.local.md`).
- Modular split via `@path/to/sub/CLAUDE.md` chain imports when content would exceed the cap.
- Total project: unlimited via modular chaining + `.claude/rules/*.md` for path-scoped guidance.
### Caching Strategy
+112
View File
@@ -0,0 +1,112 @@
> Parent context: see the root [CLAUDE.md](../CLAUDE.md) for project-wide guidelines and behavioural rules.
> Chained import: `@../CLAUDE.md`
# Installation, Testing & Release
Operational guidance for installers, smoke tests, and release management.
## Test Installation Scripts
```bash
# macOS/Linux
./install.sh
# Choose option 1 (user-level) or 2 (project-level)
# Windows
.\install.ps1
# Same options as above
# Verify after install:
ls -la ~/.claude/skills/claudeforge-skill/
ls -la ~/.claude/skills/karpathy-guidelines/
ls -la ~/.claude/skills/claude-md-drift-audit/
ls -la ~/.claude/skills/claude-md-link-check/
ls -la ~/.claude/skills/claude-md-dependency-rescan/
ls -la ~/.claude/commands/enhance-claude-md.md
ls -la ~/.claude/commands/sync-claude-md.md
ls -la ~/.claude/agents/claude-md-guardian.md
```
## Directory Layout After Install
```
~/.claude/ # user-level (project-level mirrors under ./.claude)
├── skills/
│ ├── claudeforge-skill/ # from skill/
│ │ ├── SKILL.md
│ │ ├── analyzer.py
│ │ ├── validator.py
│ │ ├── generator.py
│ │ ├── template_selector.py
│ │ ├── workflow.py
│ │ └── examples/
│ └── karpathy-guidelines/ # from skill/karpathy-guidelines/
│ └── SKILL.md
├── commands/
│ ├── enhance-claude-md.md
│ └── sync-claude-md.md
└── agents/
└── claude-md-guardian.md
```
## Smoke Test (run from repo root)
```bash
python3 - <<'PY'
import sys; sys.path.insert(0, 'skill')
from validator import BestPracticesValidator
from template_selector import TemplateSelector
from generator import ContentGenerator
assert BestPracticesValidator.MAX_RECOMMENDED_LINES == 150
for cfg in TemplateSelector.TEAM_SIZE_TEMPLATES.values():
assert cfg['target_lines'] <= 150
ctx = {'type':'fullstack','tech_stack':['typescript','python'],
'team_size':'medium','phase':'production','workflows':['cicd']}
out = ContentGenerator(ctx).generate_root_file()
assert len(out.splitlines()) <= 150
assert '## Behavioral Guidelines' in out
print('smoke ok')
PY
```
Run after any change to `skill/`, `command/`, or `agent/`.
## Manual End-to-End Tests
**Fresh project init:**
1. `mkdir test-project && cd test-project && git init && npm init -y`
2. Run `/enhance-claude-md`.
3. Confirm generated CLAUDE.md ≤ 150 lines, contains `## Behavioral Guidelines`, has tech detection right.
**Existing project enhance:**
1. Seed `CLAUDE.md` with one short section.
2. Run `/enhance-claude-md`; confirm quality score reported, missing sections proposed, `## Behavioral Guidelines` appended if absent.
**Guardian agent sync:**
1. Add a new dependency and create a new directory.
2. Open a new Claude Code session — `SessionStart` fires.
3. Confirm the agent updates Tech Stack / Project Structure and quality re-validates.
**Sync command:**
1. In a repo with stale CLAUDE.md references, run `/sync-claude-md`.
2. Confirm stale lines flagged, 150-cap enforced via split, root ↔ sub chain repaired, diff left staged for the user.
## Common Operations
**Update a reference template:** edit `skill/examples/<name>-CLAUDE.md`, then add a matching scenario to `skill/sample_input.json`.
**Update quality scoring:** edit `skill/analyzer.py``calculate_quality_score()`. Re-run the smoke test.
**Update installer:** edit `install.sh` / `install.ps1` (paths, copy logic, backup logic, hooks). Test both user-level and project-level on a throwaway directory.
## Release Process
1. Update `CHANGELOG.md` under a new version header.
2. Bump the version in `README.md`, `skill/SKILL.md`, and `.claude-plugin/plugin.json`.
3. `git tag -a vX.Y.Z -m "Release vX.Y.Z"`.
4. `git push origin vX.Y.Z`.
5. Create the GitHub release with a CHANGELOG excerpt.
Versioning is semver. See `docs/MIGRATION_V2.md` for the v1 → v2 upgrade path.
+1 -1
View File
@@ -173,7 +173,7 @@ examples/
```bash
# macOS/Linux
ls -la ~/.claude/commands/enhance-claude-md/
ls -la ~/.claude/commands/enhance-claude-md.md ~/.claude/commands/sync-claude-md.md
# Windows
dir $env:USERPROFILE\.claude\commands\enhance-claude-md\
+1 -1
View File
@@ -256,7 +256,7 @@ Claude, invoke claude-md-guardian to update CLAUDE.md
### Tip 1: Use Modular Architecture for Large Projects
If your CLAUDE.md exceeds 300 lines, split it:
If your CLAUDE.md approaches or exceeds the 150-line cap, split it (or run `/sync-claude-md` to split for you):
```bash
/enhance-claude-md
+3 -3
View File
@@ -29,7 +29,7 @@ Common issues and solutions for ClaudeForge.
2. **Verify installation paths:**
```bash
# macOS/Linux
ls -la ~/.claude/commands/enhance-claude-md/
ls -la ~/.claude/commands/enhance-claude-md.md ~/.claude/commands/sync-claude-md.md
ls -la ~/.claude/skills/claudeforge-skill/
ls -la ~/.claude/agents/claude-md-guardian.md
@@ -119,7 +119,7 @@ Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
2. **Check file length:**
```bash
wc -l CLAUDE.md
# Recommended: 20-300 lines
# Hard cap: 150 lines. Sweet spot: 50-120.
# If > 300: Consider modular architecture
```
@@ -173,7 +173,7 @@ Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
**Symptoms:**
- Single CLAUDE.md generated for large project
- File exceeds 300 lines
- File exceeds the 150-line cap (validator hook will surface this)
**Causes:**
- Project type not detected as `fullstack`
+2 -2
View File
@@ -56,8 +56,8 @@ if [ -f "CLAUDE.md" ]; then
# Check file length
lines=$(wc -l < CLAUDE.md)
if [ $lines -lt 20 ] || [ $lines -gt 400 ]; then
echo "Error: CLAUDE.md length ($lines lines) outside recommended range (20-300)"
if [ $lines -lt 20 ] || [ $lines -gt 150 ]; then
echo "Error: CLAUDE.md length ($lines lines) outside the 20-150 cap; run /sync-claude-md to split."
exit 1
fi
+1 -1
View File
@@ -8,7 +8,7 @@ Examples of modular CLAUDE.md structure for large projects.
- Full-stack projects with distinct frontend/backend
- Team size > 10 developers
- Single CLAUDE.md would exceed 300 lines
- Single CLAUDE.md would exceed the 150-line cap
- Different teams own different areas
---
+87
View File
@@ -0,0 +1,87 @@
#!/usr/bin/env python3
"""ClaudeForge Stop hook: print a 1-line CLAUDE.md health summary.
Walks the project tree from ``CLAUDE_PROJECT_DIR`` (or the cwd) and prints a
single line to stderr summarising how many CLAUDE.md files exist, how close
they are to the 150-line cap, and whether any are over. Designed to be the
last signal before a session's context is lost — drift visible to the user
without forcing them to run ``/sync-claude-md`` blindly.
Honours ``hooks/hooks-config.json`` and ``hooks/hooks-config.local.json``:
when ``stopAuditLine.enabled`` is ``false``, this script exits silently.
"""
from __future__ import annotations
import json
import os
import sys
HERE = os.path.dirname(os.path.abspath(__file__))
DEFAULT_MAX_LINES = 150
def _load_config() -> dict:
cfg: dict = {}
for name in ("hooks-config.json", "hooks-config.local.json"):
path = os.path.join(HERE, name)
if not os.path.exists(path):
continue
try:
with open(path, encoding="utf-8") as fh:
data = json.load(fh)
except (OSError, json.JSONDecodeError):
continue
cfg.update(data.get("stopAuditLine") or {})
cfg.setdefault("maxLines", (data.get("validateClaudeMd") or {}).get("maxLines"))
return cfg
def _project_root() -> str:
return os.environ.get("CLAUDE_PROJECT_DIR") or os.getcwd()
def _iter_claude_md(root: str):
skip_dirs = {".git", "node_modules", ".venv", "venv", "dist", "build", "vendor"}
for dirpath, dirnames, filenames in os.walk(root):
dirnames[:] = [d for d in dirnames if d not in skip_dirs]
for name in filenames:
if name == "CLAUDE.md":
yield os.path.join(dirpath, name)
def main() -> int:
cfg = _load_config()
if cfg.get("enabled") is False:
return 0
cap = int(cfg.get("maxLines") or DEFAULT_MAX_LINES)
warn_at = max(1, int(cap * 0.8))
total = 0
over = 0
near = 0
for path in _iter_claude_md(_project_root()):
try:
with open(path, encoding="utf-8") as fh:
lines = sum(1 for _ in fh)
except OSError:
continue
total += 1
if lines > cap:
over += 1
elif lines >= warn_at:
near += 1
if total == 0:
return 0
suffix = ""
if over:
suffix = f"{over} OVER {cap}-line cap; run /sync-claude-md"
elif near:
suffix = f"{near} near cap ({warn_at}+)"
print(f"ClaudeForge: {total} CLAUDE.md tracked{suffix}", file=sys.stderr)
return 0
if __name__ == "__main__":
sys.exit(main())
+169
View File
@@ -0,0 +1,169 @@
#!/usr/bin/env python3
"""ClaudeForge: convert a CLAUDE.md tree into an AGENTS.md for Codex / Gemini users.
Three modes:
* ``--symlink`` (default on macOS/Linux): create ``AGENTS.md`` as a symlink to
``CLAUDE.md``. Single source of truth forever. Windows falls back to
``--copy`` with a warning printed to stderr.
* ``--copy``: byte-copy ``CLAUDE.md`` → ``AGENTS.md``. Snapshot, not live-linked.
* ``--inline-chain``: walk every ``@path/.../CLAUDE.md`` import recursively and
produce a single flat ``AGENTS.md`` with every chained file inlined under a
header that names its relative path. The right choice for Codex / Gemini
because those tools don't auto-resolve Claude's ``@`` imports.
An existing ``AGENTS.md`` is backed up to ``AGENTS.md.backup.<UTC-timestamp>``
before overwrite, unless ``--force`` is passed.
Exit codes: ``0`` success, ``1`` user error (missing source, unsafe overwrite,
unknown mode), ``2`` filesystem error (permission denied, symlink unsupported).
"""
from __future__ import annotations
import argparse
import datetime as _dt
import os
import re
import shutil
import sys
from pathlib import Path
CHAIN_IMPORT = re.compile(r"^\s*@([^\s]+)\s*$")
BACKLINK_LINE = re.compile(
r"^\s*>\s*(Parent context:|Chained import:).*$", re.IGNORECASE
)
def _ts() -> str:
# Microsecond precision so two backups in the same second don't collide
# (the smoke test for the inline-chain workflow re-backs-up within ms).
return _dt.datetime.utcnow().strftime("%Y%m%d_%H%M%S_%f")
def _backup(dest: Path) -> Path | None:
if not dest.exists() and not dest.is_symlink():
return None
backup = dest.with_name(f"{dest.name}.backup.{_ts()}")
# ``shutil.move`` preserves symlinks-as-symlinks across same-filesystem.
shutil.move(str(dest), str(backup))
return backup
def _resolve_imports(root: Path, seen: set[Path]) -> list[tuple[Path, str]]:
"""Depth-first walk of ``@path`` chain imports rooted at ``root``.
Returns a list of ``(relative_path, content)`` tuples in encounter order.
Cycles are short-circuited (a file is read at most once).
"""
root = root.resolve()
if root in seen:
return []
if not root.exists():
return []
seen.add(root)
lines = root.read_text(encoding="utf-8").splitlines()
cleaned: list[str] = []
children: list[tuple[Path, str]] = []
parent_dir = root.parent
for line in lines:
m = CHAIN_IMPORT.match(line)
if m:
target = (parent_dir / m.group(1)).resolve()
if target.suffix == "" and target.is_dir():
target = target / "CLAUDE.md"
children.extend(_resolve_imports(target, seen))
# Drop the @-import line from the inlined parent body.
continue
if BACKLINK_LINE.match(line):
# Backlinks like "> Parent context: see the root [CLAUDE.md]..."
# are Claude-specific scaffolding. Drop in inline-chain output.
continue
cleaned.append(line)
rel = str(root.relative_to(Path.cwd().resolve())) if root.is_relative_to(
Path.cwd().resolve()
) else root.name
return [(rel, "\n".join(cleaned).strip() + "\n")] + children
def _do_symlink(src: Path, dest: Path) -> int:
if os.name == "nt":
print(
"claude-to-agents: symlinks on Windows require admin / dev mode; "
"falling back to --copy",
file=sys.stderr,
)
return _do_copy(src, dest)
try:
dest.symlink_to(src.name)
except OSError as exc:
print(f"claude-to-agents: symlink failed ({exc}); use --copy or --inline-chain", file=sys.stderr)
return 2
return 0
def _do_copy(src: Path, dest: Path) -> int:
shutil.copyfile(src, dest)
return 0
def _do_inline_chain(src: Path, dest: Path) -> int:
chain = _resolve_imports(src, set())
if not chain:
print(f"claude-to-agents: source {src} not found", file=sys.stderr)
return 1
out: list[str] = [
"<!-- Generated by ClaudeForge /claude-to-agents --inline-chain -->",
"<!-- Source: CLAUDE.md (this file flattens the @path chain for tools that don't auto-import). -->",
"",
]
for rel, body in chain:
out.append(f"<!-- inlined from {rel} -->")
out.append("")
out.append(body.strip())
out.append("")
dest.write_text("\n".join(out).rstrip() + "\n", encoding="utf-8")
return 0
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(prog="claude-to-agents", description=__doc__.split("\n\n")[0])
parser.add_argument("--source", default="CLAUDE.md")
parser.add_argument("--output", default="AGENTS.md")
parser.add_argument(
"--mode",
choices=("symlink", "copy", "inline-chain"),
default="symlink",
)
parser.add_argument("--force", action="store_true", help="overwrite without backup")
args = parser.parse_args(argv)
src = Path(args.source)
dest = Path(args.output)
if not src.exists():
print(f"claude-to-agents: source {src} not found", file=sys.stderr)
return 1
if (dest.exists() or dest.is_symlink()) and not args.force:
backup = _backup(dest)
if backup is not None:
print(f"claude-to-agents: backed up existing {dest} -> {backup}", file=sys.stderr)
elif args.force and (dest.exists() or dest.is_symlink()):
dest.unlink()
handlers = {
"symlink": _do_symlink,
"copy": _do_copy,
"inline-chain": _do_inline_chain,
}
rc = handlers[args.mode](src, dest)
if rc == 0:
kind = "symlink" if args.mode == "symlink" and dest.is_symlink() else "file"
print(f"claude-to-agents: wrote {dest} ({args.mode}, {kind})", file=sys.stderr)
return rc
if __name__ == "__main__":
sys.exit(main())
+12
View File
@@ -0,0 +1,12 @@
{
"$comment": "ClaudeForge shared hook config. Commit this file. Per-developer overrides go in hooks/hooks-config.local.json (gitignored).",
"validateClaudeMd": {
"enabled": true,
"maxLines": 150,
"exemptFilenameSuffix": ".local.md",
"exitCodeOnViolation": 2
},
"stopAuditLine": {
"enabled": true
}
}
+41
View File
@@ -0,0 +1,41 @@
{
"$schema": "https://json.schemastore.org/claude-code-hooks.json",
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "python3 ${CLAUDE_PLUGIN_ROOT:-${CLAUDE_PROJECT_DIR}}/hooks/validate-claude-md.py",
"timeout": 10
}
]
}
],
"InstructionsLoaded": [
{
"matcher": "session_start|nested_traversal|path_glob_match|include|compact",
"hooks": [
{
"type": "command",
"command": "python3 ${CLAUDE_PLUGIN_ROOT:-${CLAUDE_PROJECT_DIR}}/hooks/validate-claude-md.py",
"timeout": 10
}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "python3 ${CLAUDE_PLUGIN_ROOT:-${CLAUDE_PROJECT_DIR}}/hooks/audit-claude-md.py",
"timeout": 10
}
]
}
]
}
}
+123
View File
@@ -0,0 +1,123 @@
#!/usr/bin/env python3
"""ClaudeForge hook: validate every touched CLAUDE.md against the 150-line cap.
Wired into the plugin's ``hooks/hooks.json`` for both ``PostToolUse`` (after
``Edit`` or ``Write``) and ``InstructionsLoaded`` (after any of the five
``load_reason`` values fire). Reads the hook payload from stdin, extracts any
referenced file path, and exits non-zero with stderr feedback when the file
exists and exceeds the cap.
Exit codes follow the Claude Code hook contract:
- ``0`` pass
- ``2`` surface stderr to Claude as actionable feedback (do not block)
"""
from __future__ import annotations
import json
import os
import sys
DEFAULT_MAX_LINES = 150
DEFAULT_EXEMPT_SUFFIX = ".local.md"
DEFAULT_VIOLATION_RC = 2
def _load_config() -> dict:
"""Merge ``hooks-config.json`` and optional ``hooks-config.local.json``.
Local file overrides the shared one key-by-key inside ``validateClaudeMd``.
Missing files are silently ignored — the script falls back to defaults.
"""
here = os.path.dirname(os.path.abspath(__file__))
shared = os.path.join(here, "hooks-config.json")
local = os.path.join(here, "hooks-config.local.json")
cfg: dict = {}
for path in (shared, local):
if not os.path.exists(path):
continue
try:
with open(path, encoding="utf-8") as fh:
data = json.load(fh)
except (OSError, json.JSONDecodeError):
continue
validate_block = data.get("validateClaudeMd") or {}
cfg.update(validate_block)
return cfg
def _candidate_paths(payload: dict) -> list[str]:
"""Extract every file path the hook payload might be referring to.
We accept several payload shapes so the same script works for ``PostToolUse``
(tool_input.file_path) and ``InstructionsLoaded`` (path / file).
"""
paths: list[str] = []
tool_input = payload.get("tool_input") or {}
for key in ("file_path", "path", "target_file"):
value = tool_input.get(key)
if isinstance(value, str):
paths.append(value)
for key in ("path", "file", "file_path"):
value = payload.get(key)
if isinstance(value, str):
paths.append(value)
return paths
def _is_claude_md(path: str, exempt_suffix: str) -> bool:
base = os.path.basename(path)
# Personal-tier overrides (CLAUDE.local.md and any matching suffix) are
# exempt from the cap — they live outside the chained team-shared tree.
if base.endswith(exempt_suffix):
return False
return base == "CLAUDE.md" or "/.claude/rules/" in path
def main() -> int:
if sys.stdin.isatty():
return 0
raw = sys.stdin.read().strip()
if not raw:
return 0
try:
payload = json.loads(raw)
except json.JSONDecodeError:
return 0
cfg = _load_config()
if cfg.get("enabled") is False:
return 0
max_lines = int(cfg.get("maxLines", DEFAULT_MAX_LINES))
exempt_suffix = str(cfg.get("exemptFilenameSuffix", DEFAULT_EXEMPT_SUFFIX))
violation_rc = int(cfg.get("exitCodeOnViolation", DEFAULT_VIOLATION_RC))
violations: list[tuple[str, int]] = []
for path in _candidate_paths(payload):
if not _is_claude_md(path, exempt_suffix) or not os.path.exists(path):
continue
try:
with open(path, encoding="utf-8") as fh:
line_count = sum(1 for _ in fh)
except OSError:
continue
if line_count > max_lines:
violations.append((path, line_count))
if not violations:
return 0
for path, line_count in violations:
print(
f"ClaudeForge: {path} is {line_count} lines (cap is {max_lines}). "
"Run /sync-claude-md to split into chained sub-files.",
file=sys.stderr,
)
return violation_rc
if __name__ == "__main__":
sys.exit(main())
+57 -11
View File
@@ -178,7 +178,12 @@ Write-Host ""
Write-Info "Installation will create:"
Write-Host " • Skill: $skillsDir\claudeforge-skill\"
Write-Host " • Skill: $skillsDir\karpathy-guidelines\"
Write-Host "Command: $commandsDir\enhance-claude-md\"
Write-Host "Skill: $skillsDir\claude-md-drift-audit\"
Write-Host " • Skill: $skillsDir\claude-md-link-check\"
Write-Host " • Skill: $skillsDir\claude-md-dependency-rescan\"
Write-Host " • Command: $commandsDir\enhance-claude-md.md"
Write-Host " • Command: $commandsDir\sync-claude-md.md"
Write-Host " • Command: $commandsDir\claude-to-agents.md"
Write-Host " • Agent: $agentsDir\claude-md-guardian.md"
Write-Host ""
@@ -231,17 +236,48 @@ if (Test-Path $nestedKarpathy) {
}
Write-Success "Karpathy guidelines installed → $karpathyPath\"
# Install slash command
Write-Info "Installing /enhance-claude-md command..."
$commandPath = "$commandsDir\enhance-claude-md"
if (Test-Path $commandPath) {
Write-Warning "Existing command found. Creating backup..."
# Install the forked task-style audit skills as separate top-level skills
# so each is invocable standalone and discoverable by /sync-claude-md --weekly.
$auditSkills = @("claude-md-drift-audit", "claude-md-link-check", "claude-md-dependency-rescan")
foreach ($auditSkill in $auditSkills) {
Write-Info "Installing $auditSkill skill..."
$auditTarget = "$skillsDir\$auditSkill"
if (Test-Path $auditTarget) {
Write-Warning "Existing $auditSkill skill found. Creating backup..."
$backupName = "$auditSkill.backup.$(Get-Date -Format 'yyyyMMdd_HHmmss')"
Move-Item -Path $auditTarget -Destination "$skillsDir\$backupName" -Force
}
Copy-Item -Path "skill\$auditSkill" -Destination $auditTarget -Recurse -Force
$nestedAudit = "$skillPath\$auditSkill"
if (Test-Path $nestedAudit) {
Remove-Item -Path $nestedAudit -Recurse -Force
}
Write-Success "$auditSkill installed → $auditTarget\"
}
# Install slash commands. Each .md file in command/ becomes its own
# top-level command file so it registers as /<name>. README.md is skipped.
Write-Info "Installing slash commands..."
# Migrate legacy bundle directory if present.
$legacyBundle = "$commandsDir\enhance-claude-md"
if (Test-Path $legacyBundle) {
Write-Warning "Legacy command bundle found. Creating backup..."
$backupName = "enhance-claude-md.backup.$(Get-Date -Format 'yyyyMMdd_HHmmss')"
Move-Item -Path $commandPath -Destination "$commandsDir\$backupName" -Force
Move-Item -Path $legacyBundle -Destination "$commandsDir\$backupName" -Force
Write-Success "Backup created"
}
Copy-Item -Path "command" -Destination $commandPath -Recurse -Force
Write-Success "Command installed → $commandPath\"
Get-ChildItem -Path "command" -Filter "*.md" -File | Where-Object { $_.Name -ne "README.md" } | ForEach-Object {
$cmdTarget = Join-Path $commandsDir $_.Name
if (Test-Path $cmdTarget) {
Write-Warning "Existing $($_.Name) found. Creating backup..."
$backupName = "$($_.Name).backup.$(Get-Date -Format 'yyyyMMdd_HHmmss')"
Move-Item -Path $cmdTarget -Destination (Join-Path $commandsDir $backupName) -Force
}
Copy-Item -Path $_.FullName -Destination $cmdTarget -Force
Write-Success "Command installed → $cmdTarget"
}
# Install guardian agent
Write-Info "Installing claude-md-guardian agent..."
@@ -363,12 +399,22 @@ Write-Host ""
if ($scope -eq "user-level") {
Write-Host " Remove-Item -Recurse -Force ~\.claude\skills\claudeforge-skill"
Write-Host " Remove-Item -Recurse -Force ~\.claude\skills\karpathy-guidelines"
Write-Host " Remove-Item -Recurse -Force ~\.claude\commands\enhance-claude-md"
Write-Host " Remove-Item -Recurse -Force ~\.claude\skills\claude-md-drift-audit"
Write-Host " Remove-Item -Recurse -Force ~\.claude\skills\claude-md-link-check"
Write-Host " Remove-Item -Recurse -Force ~\.claude\skills\claude-md-dependency-rescan"
Write-Host " Remove-Item -Force ~\.claude\commands\enhance-claude-md.md"
Write-Host " Remove-Item -Force ~\.claude\commands\sync-claude-md.md"
Write-Host " Remove-Item -Force ~\.claude\commands\claude-to-agents.md"
Write-Host " Remove-Item -Force ~\.claude\agents\claude-md-guardian.md"
} else {
Write-Host " Remove-Item -Recurse -Force .\.claude\skills\claudeforge-skill"
Write-Host " Remove-Item -Recurse -Force .\.claude\skills\karpathy-guidelines"
Write-Host " Remove-Item -Recurse -Force .\.claude\commands\enhance-claude-md"
Write-Host " Remove-Item -Recurse -Force .\.claude\skills\claude-md-drift-audit"
Write-Host " Remove-Item -Recurse -Force .\.claude\skills\claude-md-link-check"
Write-Host " Remove-Item -Recurse -Force .\.claude\skills\claude-md-dependency-rescan"
Write-Host " Remove-Item -Force .\.claude\commands\enhance-claude-md.md"
Write-Host " Remove-Item -Force .\.claude\commands\sync-claude-md.md"
Write-Host " Remove-Item -Force .\.claude\commands\claude-to-agents.md"
Write-Host " Remove-Item -Force .\.claude\agents\claude-md-guardian.md"
}
Write-Host ""
+55 -8
View File
@@ -159,7 +159,12 @@ echo ""
print_info "Installation will create:"
echo " • Skill: $SKILLS_DIR/claudeforge-skill/"
echo " • Skill: $SKILLS_DIR/karpathy-guidelines/"
echo "Command: $COMMANDS_DIR/enhance-claude-md/"
echo "Skill: $SKILLS_DIR/claude-md-drift-audit/"
echo " • Skill: $SKILLS_DIR/claude-md-link-check/"
echo " • Skill: $SKILLS_DIR/claude-md-dependency-rescan/"
echo " • Command: $COMMANDS_DIR/enhance-claude-md.md"
echo " • Command: $COMMANDS_DIR/sync-claude-md.md"
echo " • Command: $COMMANDS_DIR/claude-to-agents.md"
echo " • Agent: $AGENTS_DIR/claude-md-guardian.md"
echo ""
@@ -203,15 +208,47 @@ cp -r skill/karpathy-guidelines "$SKILLS_DIR/karpathy-guidelines"
rm -rf "$SKILLS_DIR/claudeforge-skill/karpathy-guidelines"
print_success "Karpathy guidelines installed → $SKILLS_DIR/karpathy-guidelines/"
# Install slash command
print_info "Installing /enhance-claude-md command..."
# Install the forked task-style audit skills as separate top-level skills
# so each is invocable standalone (/claude-md-drift-audit etc.) and
# discoverable by /sync-claude-md --weekly.
for audit_skill in claude-md-drift-audit claude-md-link-check claude-md-dependency-rescan; do
print_info "Installing $audit_skill skill..."
audit_target="$SKILLS_DIR/$audit_skill"
if [ -d "$audit_target" ]; then
print_warning "Existing $audit_skill skill found. Creating backup..."
mv "$audit_target" "$audit_target.backup.$(date +%Y%m%d_%H%M%S)"
fi
cp -r "skill/$audit_skill" "$audit_target"
rm -rf "$SKILLS_DIR/claudeforge-skill/$audit_skill"
print_success "$audit_skill installed → $audit_target/"
done
# Install slash commands. Each .md file in command/ is installed as its own
# top-level command file so it registers as /<name> rather than as a nested
# /<dir>:<name>. README.md and other non-command files are skipped.
print_info "Installing slash commands..."
# Migrate legacy bundle directory if present.
if [ -d "$COMMANDS_DIR/enhance-claude-md" ]; then
print_warning "Existing command found. Creating backup..."
print_warning "Legacy command bundle found. Creating backup..."
mv "$COMMANDS_DIR/enhance-claude-md" "$COMMANDS_DIR/enhance-claude-md.backup.$(date +%Y%m%d_%H%M%S)"
print_success "Backup created"
fi
cp -r command "$COMMANDS_DIR/enhance-claude-md"
print_success "Command installed → $COMMANDS_DIR/enhance-claude-md/"
for cmd_file in command/*.md; do
cmd_basename=$(basename "$cmd_file")
# Skip the directory's own README.
if [ "$cmd_basename" = "README.md" ]; then
continue
fi
cmd_target="$COMMANDS_DIR/$cmd_basename"
if [ -f "$cmd_target" ]; then
print_warning "Existing $cmd_basename found. Creating backup..."
mv "$cmd_target" "$cmd_target.backup.$(date +%Y%m%d_%H%M%S)"
fi
cp "$cmd_file" "$cmd_target"
print_success "Command installed → $cmd_target"
done
# Install guardian agent
print_info "Installing claude-md-guardian agent..."
@@ -319,12 +356,22 @@ echo ""
if [ "$SCOPE" == "user-level" ]; then
echo " rm -rf ~/.claude/skills/claudeforge-skill"
echo " rm -rf ~/.claude/skills/karpathy-guidelines"
echo " rm -rf ~/.claude/commands/enhance-claude-md"
echo " rm -rf ~/.claude/skills/claude-md-drift-audit"
echo " rm -rf ~/.claude/skills/claude-md-link-check"
echo " rm -rf ~/.claude/skills/claude-md-dependency-rescan"
echo " rm -f ~/.claude/commands/enhance-claude-md.md"
echo " rm -f ~/.claude/commands/sync-claude-md.md"
echo " rm -f ~/.claude/commands/claude-to-agents.md"
echo " rm -f ~/.claude/agents/claude-md-guardian.md"
else
echo " rm -rf ./.claude/skills/claudeforge-skill"
echo " rm -rf ./.claude/skills/karpathy-guidelines"
echo " rm -rf ./.claude/commands/enhance-claude-md"
echo " rm -rf ./.claude/skills/claude-md-drift-audit"
echo " rm -rf ./.claude/skills/claude-md-link-check"
echo " rm -rf ./.claude/skills/claude-md-dependency-rescan"
echo " rm -f ./.claude/commands/enhance-claude-md.md"
echo " rm -f ./.claude/commands/sync-claude-md.md"
echo " rm -f ./.claude/commands/claude-to-agents.md"
echo " rm -f ./.claude/agents/claude-md-guardian.md"
fi
echo ""
+85
View File
@@ -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 (0100) 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 (50150 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
View File
@@ -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
View File
@@ -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.
+51
View File
@@ -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.
+51
View File
@@ -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
View File
@@ -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."""
+28
View File
@@ -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
+8 -4
View File
@@ -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
View File
@@ -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)"