Claude-skill-registry detect-project-type
Detect project type and configuration for generic application releases
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/detect-project-type" ~/.claude/skills/majiayu000-claude-skill-registry-detect-project-type && rm -rf "$T"
skills/data/detect-project-type/SKILL.mdDetect Project Type
Purpose
Analyzes the project directory to determine the project type (Node.js, Python, Rust, Go, Java, generic, Claude Code plugin, or monorepo) and loads or generates appropriate release configuration. This is the foundation for generic release automation that works with any application.
Input Context
The skill expects to be invoked in a project root directory. It examines:
- Configuration files (
,.release-config.json
).releaserc.json - Project markers (package.json, Cargo.toml, pyproject.toml, etc.)
- Directory structure (monorepo patterns)
- Version file locations
Workflow
1. Check for Explicit Configuration
First, check if user has provided explicit configuration:
# Check for config files in order of precedence if [ -f ".release-config.json" ]; then config_file=".release-config.json" elif [ -f ".releaserc.json" ]; then config_file=".releaserc.json" elif [ -f ".releaserc" ]; then config_file=".releaserc" else config_file="" fi
If config file exists:
- Parse JSON to extract configuration
- Validate configuration (required fields, file paths exist)
- Return configuration with
config_source: "explicit"
See Configuration Reference for schema details.
2. Auto-Detect Project Type
If no configuration file, detect project type from filesystem markers:
# Detection logic (in priority order) project_type="unknown" # Check for monorepo first (multiple package.json or project files in subdirs) if [ $(find packages -name "package.json" 2>/dev/null | wc -l) -gt 1 ] || \ [ $(find apps -name "package.json" 2>/dev/null | wc -l) -gt 1 ]; then project_type="monorepo" # Node.js project elif [ -f "package.json" ]; then project_type="nodejs" # Python project elif [ -f "pyproject.toml" ]; then project_type="python" # Rust project elif [ -f "Cargo.toml" ]; then project_type="rust" # Go project elif [ -f "go.mod" ]; then project_type="go" # Java/Gradle project elif [ -f "build.gradle" ] || [ -f "gradle.properties" ]; then project_type="java" # Maven project elif [ -f "pom.xml" ]; then project_type="java" # Claude Code plugin elif [ -f ".claude-plugin/plugin.json" ]; then project_type="claude-plugin" # Claude Code marketplace elif [ -f ".claude-plugin/marketplace.json" ]; then project_type="claude-marketplace" # Generic project with VERSION file elif [ -f "VERSION" ] || [ -f "version.txt" ] || [ -f ".version" ]; then project_type="generic" # Legacy Python (setup.py) elif [ -f "setup.py" ]; then project_type="python" else project_type="unknown" fi
3. Determine Version Files
Based on detected project type, determine version file locations:
Node.js:
version_files=("package.json") adapter="json" field="version"
Python:
# Check for multiple version sources version_files=() if [ -f "pyproject.toml" ]; then version_files+=("pyproject.toml") fi # Look for __version__.py files if [ -d "src" ]; then # Find __version__.py in src directory version_file=$(find src -name "__version__.py" | head -1) if [ -n "$version_file" ]; then version_files+=("$version_file") fi fi # Legacy setup.py if [ -f "setup.py" ]; then version_files+=("setup.py") fi
Rust:
version_files=("Cargo.toml")
Go:
# Go uses git tags for versions, no version file version_files=() version_via_tags=true
Java/Gradle:
if [ -f "gradle.properties" ]; then version_files=("gradle.properties") elif [ -f "build.gradle" ]; then version_files=("build.gradle") fi
Maven:
version_files=("pom.xml")
Claude Code Plugin:
version_files=(".claude-plugin/plugin.json")
Generic:
# Find version file by name if [ -f "VERSION" ]; then version_files=("VERSION") elif [ -f "version.txt" ]; then version_files=("version.txt") elif [ -f ".version" ]; then version_files=(".version") fi
4. Determine Changelog File
# Check for existing changelog in common formats if [ -f "CHANGELOG.md" ]; then changelog_file="CHANGELOG.md" elif [ -f "HISTORY.md" ]; then changelog_file="HISTORY.md" elif [ -f "CHANGES.md" ]; then changelog_file="CHANGES.md" elif [ -f "NEWS.md" ]; then changelog_file="NEWS.md" elif [ -f "CHANGES.rst" ]; then changelog_file="CHANGES.rst" else # Will be created changelog_file="CHANGELOG.md" fi
5. Determine Tag Pattern
# Project-specific tag patterns case "$project_type" in "nodejs"|"python"|"rust"|"generic") tag_pattern="v{version}" ;; "go") tag_pattern="v{version}" # Go convention ;; "java") tag_pattern="v{version}" ;; "claude-plugin") # Use plugin name from plugin.json plugin_name=$(jq -r '.name' .claude-plugin/plugin.json) tag_pattern="${plugin_name}-v{version}" ;; "claude-marketplace") tag_pattern="marketplace-v{version}" ;; "monorepo") tag_pattern="{package}-v{version}" ;; esac
6. Detect Monorepo Packages
For monorepo projects, scan for packages:
monorepo_packages=() # Check common monorepo patterns for pattern in "packages/*" "apps/*" "libs/*"; do for dir in $pattern; do if [ -d "$dir" ]; then # Check if directory contains a project marker if [ -f "$dir/package.json" ] || \ [ -f "$dir/Cargo.toml" ] || \ [ -f "$dir/pyproject.toml" ]; then monorepo_packages+=("$dir") fi fi done done
7. Determine Documentation Files
documentation_files=("README.md") # Add common doc patterns if [ -d "docs" ]; then documentation_files+=("docs/**/*.md") fi if [ -d "website/docs" ]; then documentation_files+=("website/docs/**/*.md") fi
8. Validation
Validate the detected configuration:
Required validations:
- At least one version file exists (unless Go project)
- Version files are readable
- Project type is not "unknown"
Warnings:
- No changelog file exists (will be created)
- No README.md exists
Output Format
Return structured configuration:
{ "project_type": "nodejs", "config_source": "auto-detected", "version_files": [ { "path": "package.json", "adapter": "json", "field": "version", "exists": true } ], "changelog_file": "CHANGELOG.md", "changelog_format": "keep-a-changelog", "tag_pattern": "v{version}", "tag_message": "Release v{version}", "conventional_commits": true, "documentation_files": [ "README.md", "docs/**/*.md" ], "monorepo": { "enabled": false, "packages": [] }, "validations": { "errors": [], "warnings": [ "No CHANGELOG.md found, will be created" ] } }
Examples
Example 1: Node.js Project
Project structure:
/ ├── package.json ├── README.md └── src/
Detection result:
{ "project_type": "nodejs", "config_source": "auto-detected", "version_files": [ { "path": "package.json", "adapter": "json", "field": "version" } ], "changelog_file": "CHANGELOG.md", "tag_pattern": "v{version}", "conventional_commits": true }
Example 2: Python Package
Project structure:
/ ├── pyproject.toml ├── src/ │ └── mypackage/ │ └── __version__.py └── README.md
Detection result:
{ "project_type": "python", "config_source": "auto-detected", "version_files": [ { "path": "pyproject.toml", "adapter": "toml", "section": "project" }, { "path": "src/mypackage/__version__.py", "adapter": "python-file" } ], "changelog_file": "CHANGELOG.md", "tag_pattern": "v{version}" }
Example 3: Rust Crate
Project structure:
/ ├── Cargo.toml ├── src/ └── README.md
Detection result:
{ "project_type": "rust", "config_source": "auto-detected", "version_files": [ { "path": "Cargo.toml", "adapter": "toml", "section": "package" } ], "changelog_file": "CHANGELOG.md", "tag_pattern": "v{version}" }
Example 4: Go Module
Project structure:
/ ├── go.mod ├── main.go └── README.md
Detection result:
{ "project_type": "go", "config_source": "auto-detected", "version_files": [], "version_via_tags": true, "changelog_file": "CHANGELOG.md", "tag_pattern": "v{version}" }
Example 5: Monorepo
Project structure:
/ ├── packages/ │ ├── lib-a/ │ │ └── package.json │ └── lib-b/ │ └── package.json └── README.md
Detection result:
{ "project_type": "monorepo", "config_source": "auto-detected", "monorepo": { "enabled": true, "packages": [ "packages/lib-a", "packages/lib-b" ] }, "tag_pattern": "{package}-v{version}", "changelog_file": "{package}/CHANGELOG.md" }
Example 6: Claude Code Plugin
Project structure:
/ ├── .claude-plugin/ │ └── plugin.json ├── skills/ └── README.md
Detection result:
{ "project_type": "claude-plugin", "config_source": "auto-detected", "version_files": [ { "path": ".claude-plugin/plugin.json", "adapter": "json", "field": "version" } ], "tag_pattern": "my-plugin-v{version}", "changelog_file": "CHANGELOG.md" }
Example 7: Explicit Configuration
Project structure:
/ ├── .release-config.json ├── VERSION └── README.md
.release-config.json:
{ "projectType": "generic", "versionFiles": ["VERSION"], "tagPattern": "release-{version}" }
Detection result:
{ "project_type": "generic", "config_source": "explicit", "version_files": [ { "path": "VERSION", "adapter": "text" } ], "tag_pattern": "release-{version}", "changelog_file": "CHANGELOG.md" }
Error Handling
Unknown project type:
{ "project_type": "unknown", "validations": { "errors": [ "Could not detect project type. Please create .release-config.json with explicit configuration." ] } }
Invalid configuration:
{ "config_source": "explicit", "validations": { "errors": [ "Configuration file .release-config.json contains invalid JSON", "versionFiles[0]: 'missing.json' does not exist" ] } }
No version files found:
{ "project_type": "generic", "validations": { "errors": [ "No version files found. Expected one of: VERSION, version.txt, package.json" ] } }
Integration Notes
This skill is invoked by the
/release command in Phase 1. The command will:
- Use the detected configuration for all subsequent phases
- Display project type and configuration to user
- Allow user to override with
argument if needed--config - Proceed with release workflow using detected/configured settings
Reference Documentation
- Version Adapters Reference - Details on reading/writing versions
- Configuration Reference - Configuration schema and examples