Claude-code-skills ln-646-project-structure-auditor
Checks file hygiene, ignore files, framework conventions, domain/layer organization, naming. Use when auditing project structure.
git clone https://github.com/levnikolaevich/claude-code-skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/levnikolaevich/claude-code-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills-catalog/ln-646-project-structure-auditor" ~/.claude/skills/levnikolaevich-claude-code-skills-ln-646-project-structure-auditor && rm -rf "$T"
skills-catalog/ln-646-project-structure-auditor/SKILL.mdPaths: File paths (
,shared/,references/) are relative to skills repo root. If not found at CWD, locate this SKILL.md directory and go up one level for repo root. If../ln-*is missing, fetch files via WebFetch fromshared/.https://raw.githubusercontent.com/levnikolaevich/claude-code-skills/master/skills/{path}
Project Structure Auditor
Type: L3 Worker
L3 Worker that audits the physical directory structure of a project against framework-specific conventions and hygiene best practices.
Purpose & Scope
- Auto-detect tech stack and apply framework-specific structure rules
- Audit 5 dimensions: file hygiene, ignore files, framework conventions, domain/layer organization, naming
- Detect project rot: leftover artifacts, inconsistent naming, junk drawer directories
- Complement code-level layer analysis with physical structure analysis
- Score and report findings per standard
formulaaudit_scoring.md - Output: file-based report to
{output_dir}/646-structure[-{domain}].md
Out of Scope:
- Code-level layer boundary violations (import analysis)
- Platform artifact cleanup (removal of files)
- Structure migration (creation/movement of directories)
- Dependency vulnerability scanning
Input
- codebase_root: string # Root directory to scan - output_dir: string # e.g., ".hex-skills/runtime-artifacts/runs/{run_id}/audit-report" # Domain-aware (optional, from coordinator) - domain_mode: "global" | "domain-aware" # Default: "global" - current_domain: string # e.g., "users", "billing" (only if domain-aware) - scan_path: string # e.g., "src/users/" (only if domain-aware)
Workflow
MANDATORY READ: Load
shared/references/two_layer_detection.md for detection methodology.
Phase 1: Detect Tech Stack
MANDATORY READ: Load
../ln-700-project-bootstrap/references/stack_detection.md -- use Detection Algorithm, Frontend Detection, Backend Detection, Structure Detection.
scan_root = scan_path IF domain_mode == "domain-aware" ELSE codebase_root # Priority 1: Read docs/project/tech_stack.md if exists IF exists(docs/project/tech_stack.md): tech_stack = parse(tech_stack.md) # Priority 2: Auto-detect from project files ELSE: Check package.json -> React/Vue/Angular/Express/NestJS Check *.csproj/*.sln -> .NET Check pyproject.toml/requirements.txt -> Python/FastAPI/Django Check go.mod -> Go Check Cargo.toml -> Rust Check pnpm-workspace.yaml/turbo.json -> Monorepo tech_stack = { language: "typescript" | "python" | "csharp" | "go" | ..., framework: "react" | "fastapi" | "aspnetcore" | ..., structure: "monolith" | "clean-architecture" | "monorepo" | ... }
Phase 2: File Hygiene Audit
MANDATORY READ: Load
references/structure_rules.md -- use "File Hygiene Rules" section. Also reference: ../ln-724-artifact-cleaner/references/platform_artifacts.md (Platform Detection Matrix, Generic Prototype Artifacts).
# Check 2.1: Build artifacts tracked in git FOR EACH artifact_dir IN structure_rules.build_artifact_dirs: IF Glob("{scan_root}/**/{artifact_dir}"): findings.append(severity: "HIGH", issue: "Build artifact directory in repo", location: path, recommendation: "Add to .gitignore, remove from tracking") # Check 2.2: Temp/log files FOR EACH pattern IN structure_rules.temp_junk_patterns: IF Glob("{scan_root}/**/{pattern}"): findings.append(severity: "MEDIUM", ...) # Check 2.3: Platform remnants (from platform_artifacts.md) FOR EACH platform IN [Replit, StackBlitz, CodeSandbox, Glitch]: IF platform indicator files found: findings.append(severity: "MEDIUM", issue: "Platform remnant: {file}", principle: "File Hygiene / Platform Artifacts") # Check 2.4: Multiple lock files lock_files = Glob("{scan_root}/{package-lock.json,yarn.lock,pnpm-lock.yaml,bun.lockb}") IF len(lock_files) > 1: findings.append(severity: "HIGH", issue: "Multiple lock files: {lock_files}", recommendation: "Keep one lock file matching your package manager") # Check 2.6: Large binaries tracked by git FOR EACH file IN Glob("{scan_root}/**/*.{zip,tar,gz,rar,exe,dll,so,dylib,jar,war}"): findings.append(severity: "MEDIUM", issue: "Binary file tracked: {file}", recommendation: "Use Git LFS or remove from repository")
Phase 3: Ignore File Quality
MANDATORY READ: Load
references/structure_rules.md -- use "Ignore File Rules" section. Also reference: ../ln-733-env-configurator/references/gitignore_secrets.template (secrets baseline), ../ln-731-docker-generator/references/dockerignore.template (dockerignore baseline).
# Check 3.1: .gitignore exists IF NOT exists(.gitignore): findings.append(severity: "HIGH", issue: "No .gitignore file") ELSE: content = Read(.gitignore) # Check 3.1a: Stack-specific entries present required_entries = get_required_gitignore(tech_stack) FOR EACH entry IN required_entries: IF entry NOT covered in .gitignore: findings.append(severity: "MEDIUM", issue: ".gitignore missing: {entry}") # Check 3.1b: Secrets protection (compare with gitignore_secrets.template) secrets_patterns = [".env", ".env.local", "*.pem", "*.key", "secrets/"] FOR EACH pattern IN secrets_patterns: IF pattern NOT in .gitignore: findings.append(severity: "HIGH", issue: ".gitignore missing secrets: {pattern}", principle: "Ignore Files / Secrets") # Check 3.1c: IDE/OS entries ide_patterns = [".vscode/", ".idea/", "*.swp", ".DS_Store", "Thumbs.db"] missing_ide = [p for p in ide_patterns if p NOT covered in .gitignore] IF len(missing_ide) > 2: findings.append(severity: "LOW", issue: ".gitignore missing IDE/OS: {missing_ide}") # Check 3.2: .dockerignore IF exists(Dockerfile) AND NOT exists(.dockerignore): findings.append(severity: "MEDIUM", issue: "Dockerfile exists but no .dockerignore", recommendation: "Create .dockerignore to reduce build context") ELIF exists(.dockerignore): FOR EACH required IN [node_modules, .git, .env, "*.log"]: IF required NOT in .dockerignore: findings.append(severity: "LOW", ...)
Phase 4: Framework Convention Compliance
MANDATORY READ: Load
references/structure_rules.md -- use framework-specific section matching detected tech_stack.
rules = get_framework_rules(tech_stack, structure_rules.md) # Returns: {expected_dirs, forbidden_placements, co_location_rules} # Check 4.1: Expected directories exist FOR EACH dir IN rules.expected_dirs WHERE dir.required == true: IF NOT exists(dir.path): findings.append(severity: "MEDIUM", issue: "Expected directory missing: {dir.path}", principle: "Framework Convention / {tech_stack.framework}") # Check 4.2: Source code in wrong locations FOR EACH rule IN rules.forbidden_placements: matches = Glob(rule.glob_pattern, scan_root) FOR EACH match IN matches: IF match NOT IN rules.exceptions: findings.append(severity: "HIGH", issue: "Source file in wrong location: {match}", recommendation: "Move to {rule.expected_location}") # Check 4.3: Co-location rules (React feature folders) IF tech_stack.framework IN ["react", "vue", "angular", "svelte"]: component_dirs = Glob("{scan_root}/**/components/*/") colocation_count = 0 FOR EACH dir IN component_dirs: has_test = Glob("{dir}/*.{test,spec}.{ts,tsx,js,jsx}") IF has_test: colocation_count += 1 # Only flag if project already uses co-location (>50%) IF colocation_count > len(component_dirs) * 0.5: FOR EACH dir IN component_dirs: IF NOT has_test_for(dir): findings.append(severity: "LOW", issue: "Component missing co-located test: {dir}")
Phase 5: Domain/Layer Organization
# Check 5.1: Junk drawer detection junk_thresholds = structure_rules.junk_drawer_thresholds FOR EACH dir IN Glob("{scan_root}/**/"): dir_name = basename(dir) IF dir_name IN junk_thresholds: file_count = len(Glob("{dir}/*.*")) IF file_count > junk_thresholds[dir_name].max_files: findings.append(severity: junk_thresholds[dir_name].severity, issue: "Junk drawer directory: {dir} ({file_count} files)", principle: "Organization / Module Cohesion", recommendation: "Split into domain-specific modules or feature folders") # Check 5.2: Root directory cleanliness root_files = Glob("{scan_root}/*") # Direct children only source_in_root = [f for f in root_files if f.ext IN source_extensions AND basename(f) NOT IN allowed_root_files] IF len(source_in_root) > 0: findings.append(severity: "MEDIUM", issue: "Source files in project root: {source_in_root}", recommendation: "Move to src/ or appropriate module directory") config_in_root = [f for f in root_files if is_config_file(f)] IF len(config_in_root) > 15: findings.append(severity: "LOW", issue: "Excessive config files in root ({len(config_in_root)})", recommendation: "Move non-essential configs to config/ directory") # Check 5.3: Consistent module structure across domains IF domain_mode == "global" AND len(detect_domains(scan_root)) >= 2: domains = detect_domains(scan_root) structures = {d.name: set(subdirectory_names(d.path)) for d in domains} all_subdirs = union(structures.values()) FOR EACH domain IN domains: missing = all_subdirs - structures[domain] IF 0 < len(missing) < len(all_subdirs) * 0.5: findings.append(severity: "LOW", issue: "Inconsistent domain structure: {domain.name} missing {missing}", recommendation: "Align domain module structures for consistency")
Phase 6: Naming Conventions
MANDATORY READ: Load
references/structure_rules.md -- use "Naming Convention Rules" section.
naming_rules = get_naming_rules(tech_stack) # Returns: {file_case, dir_case, test_pattern, component_case} # Check 6.1: File naming consistency violations = [] FOR EACH file IN Glob("{scan_root}/**/*.{ts,tsx,js,jsx,py,cs,go}"): expected_case = naming_rules.file_case IF is_component(file) AND NOT matches_case(basename(file), expected_case): violations.append(file) IF len(violations) > 0: pct = len(violations) / total_source_files * 100 severity = "HIGH" if pct > 30 else "MEDIUM" if pct > 10 else "LOW" findings.append(severity, issue: "Naming violations: {len(violations)} files ({pct}%)", principle: "Naming / {naming_rules.file_case}") # Check 6.2: Directory naming consistency dirs = get_all_source_dirs(scan_root) dir_cases = classify_cases(dirs) # Count per case style dominant = max(dir_cases) inconsistent = [d for d in dirs if case_of(d) != dominant] IF len(inconsistent) > 0: findings.append(severity: "LOW", issue: "Inconsistent directory naming: {len(inconsistent)} dirs use mixed case") # Check 6.3: Test file naming pattern test_files = Glob("{scan_root}/**/*.{test,spec}.{ts,tsx,js,jsx}") + Glob("{scan_root}/**/*_test.{py,go}") IF len(test_files) > 0: patterns_used = detect_test_patterns(test_files) # .test. vs .spec. vs _test IF len(patterns_used) > 1: findings.append(severity: "LOW", issue: "Mixed test naming patterns: {patterns_used}", recommendation: "Standardize to {dominant_test_pattern}")
Phase 7: Score + Report + Return
MANDATORY READ: Load
shared/references/audit_worker_core_contract.md, shared/references/audit_scoring.md, and shared/templates/audit_worker_report_template.md.
When summaryArtifactPath is present, write the JSON summary to that exact path. When summaryArtifactPath is absent, write the standalone runtime summary under .hex-skills/runtime-artifacts/runs/{run_id}/evaluation-worker/{worker}--{identifier}.json and optionally echo the same summary in structured output.
# 7a: Calculate score via shared formula # 7b: Build report in memory using the shared audit worker template # 7c: Populate DATA-EXTENDED with: # tech_stack # dimensions.file_hygiene / ignore_files / framework_conventions / domain_organization / naming_conventions # junk_drawers # naming_dominant_case # naming_violations_pct # 7d: Write report (atomic single Write call) Write to {output_dir}/ln-646--{identifier}.md # 7e: Return summary Report written: .hex-skills/runtime-artifacts/runs/{run_id}/audit-report/ln-646--{identifier}.md Score: X.X/10 | Issues: N (C:N H:N M:N L:N)
Scoring
MANDATORY READ: Load
shared/references/audit_worker_core_contract.md and shared/references/audit_scoring.md.
Severity mapping:
- HIGH: Build artifacts tracked, missing .gitignore, source in wrong location, multiple lock files, missing secrets in .gitignore. Exception: Build artifacts in Git LFS -> skip
- MEDIUM: Missing framework dirs, junk drawers, temp files, platform remnants, missing stack-specific gitignore entries, naming violations >10%
- LOW: IDE/OS patterns missing, inconsistent dir naming, mixed test patterns, minor config issues
Critical Rules
MANDATORY READ: Load
shared/references/audit_worker_core_contract.md.
- Auto-detect, never assume: Always detect tech stack before applying framework rules
- No false positives on conventions: Apply framework rules ONLY for detected stack
- Security-first: Missing secrets in .gitignore = HIGH
- Complement, not overlap: Do NOT check import-level layer violations (separate worker scope)
- Report only, never modify: Never move/delete files (separate migration/cleanup workers)
- Reuse platform detection: Reference platform artifact patterns from references
- Co-location awareness: Only flag missing co-location if project already uses the pattern (>50%)
- Evidence always: Include file paths for every finding
Definition of Done
MANDATORY READ: Load
shared/references/audit_worker_core_contract.md.
- Tech stack detected (from
or auto-detection)docs/project/tech_stack.md - File hygiene checked: build artifacts, temp files, platform remnants, lock files, binaries
- Ignore files audited: .gitignore completeness, secrets protection, .dockerignore if Dockerfile present
- Framework conventions applied: expected dirs, forbidden placements, co-location rules
- Domain/layer organization checked: junk drawers, root cleanliness, cross-domain consistency
- Naming conventions validated: file/dir/test naming patterns
- If domain-aware: all Glob scoped to
, findings tagged with domainscan_path - Score calculated per
audit_scoring.md - Report written to
(atomic single Write call){output_dir}/646-structure[-{domain}].md - Summary written per contract
Reference Files
- Structure rules:
references/structure_rules.md - Stack detection:
../ln-700-project-bootstrap/references/stack_detection.md - Platform artifacts:
../ln-724-artifact-cleaner/references/platform_artifacts.md - Gitignore secrets:
../ln-733-env-configurator/references/gitignore_secrets.template - Dockerignore baseline:
../ln-731-docker-generator/references/dockerignore.template
Version: 1.0.0 Last Updated: 2026-02-28