ln-646-project-structure-auditor

Checks file hygiene, ignore files, framework conventions, domain/layer organization, naming. Use when auditing project structure.

310 stars

Best use case

ln-646-project-structure-auditor is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Checks file hygiene, ignore files, framework conventions, domain/layer organization, naming. Use when auditing project structure.

Teams using ln-646-project-structure-auditor should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/ln-646-project-structure-auditor/SKILL.md --create-dirs "https://raw.githubusercontent.com/levnikolaevich/claude-code-skills/main/skills-catalog/ln-646-project-structure-auditor/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/ln-646-project-structure-auditor/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How ln-646-project-structure-auditor Compares

Feature / Agentln-646-project-structure-auditorStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Checks file hygiene, ignore files, framework conventions, domain/layer organization, naming. Use when auditing project structure.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

> **Paths:** File paths (`shared/`, `references/`, `../ln-*`) 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 `shared/` is missing, fetch files via WebFetch from `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 `audit_scoring.md` formula
- 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`.

If `summaryArtifactPath` is present, write JSON summary per `shared/references/audit_summary_contract.md`. Compact text output is fallback only.

```
# 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)
IF domain_mode == "domain-aware":
  Write to {output_dir}/646-structure-{current_domain}.md
ELSE:
  Write to {output_dir}/646-structure.md

# 7e: Return summary
Report written: .hex-skills/runtime-artifacts/runs/{run_id}/audit-report/646-structure[-{domain}].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 `docs/project/tech_stack.md` or auto-detection)
- [ ] 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 `scan_path`, findings tagged with domain
- [ ] Score calculated per `audit_scoring.md`
- [ ] Report written to `{output_dir}/646-structure[-{domain}].md` (atomic single Write call)
- [ ] 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

Related Skills

ln-743-test-infrastructure

310
from levnikolaevich/claude-code-skills

Sets up test infrastructure with Vitest, xUnit, and pytest. Use when adding testing frameworks and sample tests to a project.

ln-721-frontend-restructure

310
from levnikolaevich/claude-code-skills

Scaffolds new React projects or restructures monoliths to component-based architecture. Use when setting up frontend structure.

ln-720-structure-migrator

310
from levnikolaevich/claude-code-skills

Scaffolds new or restructures existing projects to Clean Architecture. Use when setting up project structure.

ln-700-project-bootstrap

310
from levnikolaevich/claude-code-skills

Bootstraps projects to production-ready structure. Use when creating new or transforming existing projects.

ln-654-resource-lifecycle-auditor

310
from levnikolaevich/claude-code-skills

Checks session scope mismatch, missing cleanup, pool config, error path leaks, resource holding. Use when auditing resource lifecycle.

ln-653-runtime-performance-auditor

310
from levnikolaevich/claude-code-skills

Checks blocking IO in async, unnecessary allocations, sync sleep, string concat in loops, redundant copies. Use when auditing runtime performance.

ln-652-transaction-correctness-auditor

310
from levnikolaevich/claude-code-skills

Checks transaction scope, missing rollback handling, long-held transactions, trigger/notify interaction. Use when auditing transaction correctness.

ln-651-query-efficiency-auditor

310
from levnikolaevich/claude-code-skills

Checks redundant fetches, N+1 loops, over-fetching, missing bulk operations, wrong caching scope. Use when auditing query efficiency.

ln-650-persistence-performance-auditor

310
from levnikolaevich/claude-code-skills

Coordinates persistence and performance audit across queries, transactions, runtime, and resource lifecycle. Use when auditing data layer performance.

ln-647-env-config-auditor

310
from levnikolaevich/claude-code-skills

Checks env var config sync, missing defaults, naming conventions, startup validation. Use when auditing environment configuration.

ln-644-dependency-graph-auditor

310
from levnikolaevich/claude-code-skills

Builds dependency graph, detects cycles, validates boundary rules, calculates coupling metrics (Ca/Ce/I). Use when auditing dependency structure.

ln-643-api-contract-auditor

310
from levnikolaevich/claude-code-skills

Checks layer leakage in method signatures, missing DTOs, entity leakage to API, inconsistent error contracts. Use when auditing API contracts.