agentleFS
d-o-hubd-o-hub/github-template-ai-agents/.agents/skills/shell-script-quality/SKILL.md

shell-script-quality

Skill2 starsChanged 9 days agoMITView on GitHub

Lint and test shell scripts using ShellCheck and BATS. Use this skill when checking bash/sh scripts for errors, writing shell script tests, fixing ShellCheck warnings, setting up CI/CD for shell scripts, or improving bash code quality — even if they just say "fix this script" or "add tests for the shell script". Not for static-analysis, cicd-pipeline.

  • Installs packages

The file

We split this skill into the rules it gives an agent

5 rules. About 0 are common, 2 are distinctive, and 3 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 3

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Note: When searching for patterns across scripts, use the dedicated Grep Tool (with pattern/type parameters) instead of calling grep or …

    line 36
  2. Very specific:

    required: check has issueThreshold: 0 and counts issues at *any* severity.

    line 52
  3. Distinctive:

    If fails: review errors, fix, re-run.

    line 208
  4. Very specific:

    Only proceed when validation passes → bats tests/script.bats.

    line 209
  5. Distinctive:

    If tests fail, return to step 1.

    line 210

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Shell Script Quality

Comprehensive shell script linting and testing using ShellCheck and BATS with 2025 best practices.

When to Use

  • User asks to check bash/sh scripts for errors or fix ShellCheck warnings
  • Need to write shell script tests or set up CI/CD for shell scripts
  • Even if they just say "fix this script" or "add tests for the shell script"

Quick Start

Copy this workflow checklist and track your progress:

Shell Script Quality Workflow:
- [ ] Step 1: Lint with ShellCheck
- [ ] Step 2: Fix reported issues
- [ ] Step 3: Write BATS tests
- [ ] Step 4: Verify tests pass
- [ ] Step 5: Integrate into CI/CD

Core Workflow

Step 1: Lint with ShellCheck

Note: When searching for patterns across scripts, use the dedicated Grep Tool (with pattern/type parameters) instead of calling grep or find directly, as per AGENTS.md.

# Lint single file
shellcheck script.sh

# Lint all scripts
find scripts -name "*.sh" -exec shellcheck {} +

# Use config file if present
shellcheck -x script.sh

Step 1b: Verify new code at FULL severity (required before push)

This repo's quality_gate.sh runs shellcheck --severity=error, but Codacy's required check has issueThreshold: 0 and counts issues at any severity. Code that passes the local gate can therefore still block a merge. Verify the files you touched at full severity, where all levels are findings:

# Full severity on the files you changed
shellcheck path/to/changed.sh

# Delta check: compare full severity between HEAD and your branch, so you only
# see NEW issues. A blanket repo-wide full-severity run is NOT viable here --
# ~127 pre-existing findings would drown the signal.
git stash -q
shellcheck $(git ls-files '*.sh') 2>&1 | grep -cE '^In |SC[0-9]+' > /tmp/opencode/sc-base
git stash pop -q
shellcheck $(git ls-files '*.sh') 2>&1 | grep -cE '^In |SC[0-9]+' > /tmp/opencode/sc-new
diff /tmp/opencode/sc-base /tmp/opencode/sc-new && echo "no new findings"

Query the real verdict rather than guessing:

codacy pull-request <PR> -o json   # newIssues, quality.gate, per-issue resultDataId

Two codes that found real defects here, and are worth reading as bugs rather than style:

CodeWhy it matters
SC2235(...) is a subshell. VAR+=(x) inside it never reaches the parent, so a later [[ " ${VAR[*]} " =~ " x " ]] test silently never matches — a latent false green.
SC2034"Appears unused" across a source boundary is usually a real contract: the variable is read by the sourcing script. Fix with a file-scope disable plus a stated reason, or fix the contract.

Common fixes: See SHELLCHECK.md for fix patterns

Step 2: Fix Reported Issues

Apply fixes for common warnings:

  • SC2086: Quote variables: "$var" not $var
  • SC2155: Separate declaration and assignment
  • SC2181: Check exit code directly with if ! command

For detailed fixes: See SHELLCHECK.md

Step 3: Write BATS Tests

#!/usr/bin/env bats

setup() {
    source "$BATS_TEST_DIRNAME/../scripts/example.sh"
}

@test "function succeeds with valid input" {
    run example_function "test"
    [ "$status" -eq 0 ]
    [ -n "$output" ]
}

@test "function fails with invalid input" {
    run example_function ""
    [ "$status" -ne 0 ]
    [[ "$output" =~ "ERROR" ]]
}

Test patterns: See BATS.md for comprehensive testing guide

Step 4: Run Tests

# Run all tests
bats tests/

# Run with verbose output
bats -t tests/

# Run specific file
bats tests/example.bats

If tests fail: Review error output, fix issues, re-run validation

Step 5: CI/CD Integration

GitHub Actions: See CI-CD.md for complete workflows

Quick integration:

On an Ubuntu runner after checkout, install the tools rather than using a third-party action on a mutable branch. Adapt the script paths to the project.

- name: Install shell checks
  run: |
    sudo apt-get update
    sudo apt-get install -y shellcheck bats
- name: ShellCheck
  run: shellcheck scripts/*.sh
- name: Run BATS
  run: bats tests/

Script Template

#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
error_exit() { echo "ERROR: $1" >&2; exit "${2:-1}"; }
main() {
    [[ $# -lt 1 ]] && { echo "Usage: $0 <argument>" >&2; exit 1; }
    # Your logic here
}
[[ "${BASH_SOURCE[0]}" == "${0}" ]] && main "$@"

Installation

brew install shellcheck         # macOS | sudo apt-get install shellcheck # Linux
brew install bats-core          # macOS | sudo apt-get install bats       # Linux

Configuration

.shellcheckrc in project root: shell=bash, disable=SC1090, enable=all, source-path=SCRIPTDIR. See CONFIG.md.

Testing Claude Code Plugins

@test "plugin script works" {
    export CLAUDE_PLUGIN_ROOT="$BATS_TEST_DIRNAME/.."
    run bash "$CLAUDE_PLUGIN_ROOT/scripts/search.sh" "query"
    [ "$status" -eq 0 ]
}

@test "hook provides suggestions" {
    local input='{"tool":"Edit","params":{"file_path":"test.txt"}}'
    run bash "$HOOK_DIR/pre-edit.sh" <<< "$input"
    [ "$status" -eq 0 ]
    echo "$output" | jq empty
}

More patterns: See PATTERNS.md

Troubleshooting

  • ShellCheck: SC1090 → add # shellcheck source=path/to/file.sh. False positives → # shellcheck disable=SCxxxx.
  • BATS: Tests interfere → ensure proper teardown(). Can't source → add main execution guard. Path issues → use $BATS_TEST_DIRNAME.

See TROUBLESHOOTING.md.

Validation Loop Pattern

  1. Make changes → shellcheck script.sh immediately.
  2. If fails: review errors, fix, re-run.
  3. Only proceed when validation passes → bats tests/script.bats.
  4. If tests fail, return to step 1.

References

  • SHELLCHECK.md - Complete ShellCheck guide and fix patterns
  • BATS.md - BATS testing comprehensive guide
  • CI-CD.md - GitHub Actions, GitLab CI, pre-commit hooks
  • PATTERNS.md - Common patterns and examples
  • CONFIG.md - Configuration and setup details
  • TROUBLESHOOTING.md - Common issues and solutions

See Also

  • static-analysis — Linter triage across any language
  • cicd-pipeline — CI/CD for shell script testing

Rationalizations

RationalizationReality
"ShellCheck warnings are false positives"Most SC warnings catch real bugs; suppress with documented reason, not dismissal.
"The local gate passed, so the code is clean"The gate runs --severity=error; Codacy's required check counts issues at any severity. Warning-level findings pass locally and still block the merge.
"Just run full-severity ShellCheck on the whole repo"~127 findings already exist at full severity. Use a base-vs-branch delta so new issues are visible without the noise.
"BATS tests take too long to write"Untested scripts break silently in production; test time is investment, not waste.
"set -e is too strict for my script"Scripts without -e silently swallow errors and leave systems in inconsistent states.

Red Flags

  • Running shell scripts without set -euo pipefail
  • Skipping ShellCheck linting before committing shell scripts
  • Trusting --severity=error as proof of Codacy-clean shell code
  • Checking codacy pull-request only after discovering the PR is blocked
  • Suppressing SC warnings without documenting the reason and date

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.