π¨ CRITICAL GUIDELINES
Windows File Path Requirements
MANDATORY: Always Use Backslashes on Windows for File Paths
When using Edit or Write tools on Windows, you MUST use backslashes (
) in file paths, NOT forward slashes (/
).
Examples:
-
β WRONG: D:/repos/project/file.tsx
-
β CORRECT: D:\repos\project\file.tsx
This applies to:
-
Edit tool file_path parameter
-
Write tool file_path parameter
-
All file operations on Windows systems
Documentation Guidelines
NEVER create new documentation files unless explicitly requested by the user.
-
Priority: Update existing README.md files rather than creating new documentation
-
Repository cleanliness: Keep repository root clean - only README.md unless user requests otherwise
-
Style: Documentation should be concise, direct, and professional - avoid AI-generated tone
-
User preference: Only create additional .md files when user specifically asks for documentation
ShellCheck CI/CD Integration (2025)
ShellCheck: Non-Negotiable in 2025
ShellCheck is now considered mandatory in modern bash workflows (2025 best practices):
Latest Version: v0.11.0 (August 2025)
What's New:
-
Full Bash 5.3 support (${| cmd; } and source -p )
-
New warnings: SC2327/SC2328 (capture group issues)
-
POSIX.1-2024 compliance: SC3013 removed (-ot/-nt/-ef now POSIX standard)
-
Enhanced static analysis capabilities
-
Improved performance and accuracy
Why Mandatory?
-
Catches subtle bugs before production
-
Prevents common security vulnerabilities
-
Enforces consistent code quality
-
Required by most DevOps teams
-
Standard in enterprise environments
-
Supports latest POSIX.1-2024 standard
Installation
Ubuntu/Debian
apt-get install shellcheck
macOS
brew install shellcheck
Alpine (Docker)
apk add shellcheck
Windows (WSL/Git Bash)
choco install shellcheck
Or download binary
wget https://github.com/koalaman/shellcheck/releases/latest/download/shellcheck-stable.linux.x86_64.tar.xz tar -xf shellcheck-stable.linux.x86_64.tar.xz sudo cp shellcheck-stable/shellcheck /usr/local/bin/
GitHub Actions Integration
Mandatory Pre-Merge Check
.github/workflows/shellcheck.yml
name: ShellCheck
on: pull_request: paths: - '**.sh' - '**Dockerfile' push: branches: [main]
jobs: shellcheck: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3
- name: Run ShellCheck
uses: ludeeus/action-shellcheck@master
with:
severity: warning
format: gcc # or: tty, json, checkstyle
scandir: './scripts'
# Fail on any issues
ignore_paths: 'node_modules'
# Block merge on failures
- name: Annotate PR
if: failure()
uses: actions/github-script@v6
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: 'β ShellCheck validation failed. Fix issues before merging.'
})
Azure DevOps Integration
azure-pipelines.yml
trigger:
- main
pr:
- main
stages:
- stage: Validate
jobs:
-
job: ShellCheck pool: vmImage: 'ubuntu-24.04'
steps:
-
script: | sudo apt-get install -y shellcheck displayName: 'Install ShellCheck'
-
script: | find . -name "*.sh" -type f | xargs shellcheck --format=gcc --severity=warning displayName: 'Run ShellCheck' failOnStderr: true
-
task: PublishTestResults@2 condition: always() inputs: testResultsFormat: 'JUnit' testResultsFiles: '**/shellcheck-results.xml' failTaskOnFailedTests: true
-
-
Git Hooks (Pre-Commit)
.git/hooks/pre-commit
#!/usr/bin/env bash set -o errexit set -o nounset set -o pipefail
Find all staged .sh files
mapfile -t STAGED_SH < <(git diff --cached --name-only --diff-filter=ACMR | grep '.sh$' || true)
if [ ${#STAGED_SH[@]} -eq 0 ]; then exit 0 fi
echo "Running ShellCheck on staged files..."
Run ShellCheck
shellcheck --format=gcc --severity=warning "${STAGED_SH[@]}"
if [ $? -ne 0 ]; then echo "β ShellCheck failed. Fix issues before committing." exit 1 fi
echo "β ShellCheck passed" exit 0
Install Pre-Commit Hook:
chmod +x .git/hooks/pre-commit
Or use pre-commit framework
.pre-commit-config.yaml
repos:
- repo: https://github.com/shellcheck-py/shellcheck-py
rev: v0.11.0.0
hooks:
- id: shellcheck args: ['--severity=warning']
Install
pip install pre-commit pre-commit install
VS Code Integration
// .vscode/settings.json { "shellcheck.enable": true, "shellcheck.run": "onType", "shellcheck.executablePath": "/usr/local/bin/shellcheck", "shellcheck.exclude": ["SC1090", "SC1091"], // Optional excludes "shellcheck.customArgs": [ "-x", // Follow source files "--severity=warning" ] }
Docker Build Integration
Dockerfile with ShellCheck validation
FROM alpine:3.19 AS builder
Install ShellCheck
RUN apk add --no-cache shellcheck bash
Copy scripts
COPY scripts/ /scripts/
Validate all scripts before continuing
RUN find /scripts -name "*.sh" -type f -exec shellcheck --severity=warning {} +
Final stage
FROM alpine:3.19 COPY --from=builder /scripts/ /scripts/ RUN chmod +x /scripts/*.sh
ENTRYPOINT ["/scripts/entrypoint.sh"]
Common ShellCheck Rules (2025)
New in v0.11.0: SC2327/SC2328 - Capture Groups
β Bad - Capture groups may not work as expected
if [[ "$string" =~ ([0-9]+).([0-9]+) ]]; then echo "$1" # Wrong: $1 is script arg, not capture group fi
β Good - Use BASH_REMATCH array
if [[ "$string" =~ ([0-9]+).([0-9]+) ]]; then echo "${BASH_REMATCH[1]}.${BASH_REMATCH[2]}" fi
SC2294: eval Negates Array Benefits (New)
β Bad - eval defeats array safety
eval "command ${array[@]}"
β Good - Direct array usage
command "${array[@]}"
SC2295: Quote Expansions Inside ${}
β Bad
echo "${var-$default}" # $default not quoted
β Good
echo "${var-"$default"}"
SC2086: Quote Variables
β Bad
file=$1 cat $file # Fails if filename has spaces
β Good
file=$1 cat "$file"
SC2046: Quote Command Substitution
β Bad
for file in $(find . -name "*.txt"); do echo $file done
β Good
find . -name "*.txt" -print0 | while IFS= read -r -d '' file; do echo "$file" done
SC2155: Separate Declaration and Assignment
β Bad
local result=$(command) # Hides command exit code
β Good
local result result=$(command)
SC2164: Use cd || exit
β Bad
cd /some/directory ./script.sh # Runs in wrong dir if cd fails
β Good
cd /some/directory || exit 1 ./script.sh
Google Shell Style Guide (50-Line Limit)
2025 recommendation: Keep scripts under 50 lines:
β Bad: 500-line monolithic script
#!/usr/bin/env bash
... 500 lines of code ...
β Good: Modular scripts < 50 lines each
lib/logging.sh (20 lines)
log_info() { echo "[INFO] $"; } log_error() { echo "[ERROR] $" >&2; }
lib/validation.sh (30 lines)
validate_input() { ... } check_dependencies() { ... }
main.sh (40 lines)
source "$(dirname "$0")/lib/logging.sh" source "$(dirname "$0")/lib/validation.sh"
main() { validate_input "$@" check_dependencies
... core logic ...
}
main "$@"
Enforce in CI/CD
Fail Build on Issues
Strict enforcement
- name: ShellCheck (Strict)
run: |
shellcheck --severity=warning scripts/*.sh
Exit code 1 fails the build
Advisory only (warnings but don't fail)
- name: ShellCheck (Advisory)
run: |
shellcheck --severity=warning scripts/*.sh || true
Logs warnings but doesn't fail
Generate Reports
JSON format for parsing
shellcheck --format=json scripts/*.sh > shellcheck-report.json
GitHub annotations format
shellcheck --format=gcc scripts/*.sh
Human-readable
shellcheck --format=tty scripts/*.sh
Modern Error Handling Trio (2025)
Always use with ShellCheck validation:
#!/usr/bin/env bash
Modern error handling (non-negotiable in 2025)
set -o errexit # Exit on command failure set -o nounset # Exit on undefined variable set -o pipefail # Exit on pipe failure
ShellCheck approved
main() { local config_file="${1:?Config file required}"
if [[ ! -f "$config_file" ]]; then echo "Error: Config file not found: $config_file" >&2 return 1 fi
Safe command execution
local result result=$(process_config "$config_file")
echo "$result" }
main "$@"
Best Practices (2025)
-
Run ShellCheck in CI/CD (mandatory)
-
Use pre-commit hooks to catch issues early
-
Keep scripts under 50 lines (Google Style Guide)
-
Use modern error handling trio (errexit, nounset, pipefail)
-
Fix all warnings before merging
-
Document any disabled rules with reasoning
-
Integrate with IDE for real-time feedback
Resources
-
ShellCheck
-
Google Shell Style Guide
-
ShellCheck GitHub Action