| name | shell-scripting |
| description | Standards for Bash and PowerShell scripts in DAAF: preambles, quoting, error handling, cleanup, testing. Use when writing or reviewing .sh/.ps1 files (hooks, lifecycle, utilities). Not runtime safety ā that is bash-safety.sh hook. |
| metadata | {"audience":"any-agent","domain":"scripting-standards"} |
Shell Scripting Standards
Coding quality standards and best practices for all .sh (Bash) and .ps1 (PowerShell) scripts within DAAF. Covers preamble conventions, quoting discipline, error handling philosophy, signal/cleanup patterns, Docker interaction, output formatting, testing strategies, and cross-platform gotchas. Use when authoring new shell scripts (hooks, Docker lifecycle, utilities), reviewing existing scripts for compliance, debugging script failures, or setting up CI for shell code.
Boundary with bash-safety.sh: This skill governs how to write good scripts (coding quality). The bash-safety.sh hook governs what commands are safe to run (runtime safety enforcement). A script can follow every standard in this skill and still be blocked by bash-safety.sh if it contains a dangerous command like rm -rf /. Conversely, a script that passes bash-safety.sh may still be poorly written if it ignores these standards.
How to Use This Skill
Reference File Structure
| File | Purpose | When to Read |
|---|
bash-standards.md | Preambles, quoting, variables, ShellCheck, signal handling | Writing or reviewing any .sh file |
powershell-standards.md | Preambles, dual error system, defensive coding, PSScriptAnalyzer | Writing or reviewing any .ps1 file |
error-handling.md | Fail-closed philosophy, output conventions, exit codes, Docker errors, dependency validation | Designing error paths for any script |
testing.md | BATS, Pester, CI workflows, Docker mocking, test taxonomy | Setting up or running script tests |
gotchas.md | Bash traps, PowerShell surprises, cross-platform pitfalls | Debugging unexpected script behavior |
Reading Order
- Writing a Bash script? Start with
bash-standards.md, then error-handling.md
- Writing a PowerShell script? Start with
powershell-standards.md, then error-handling.md
- Setting up tests? Read
testing.md
- Script behaving unexpectedly? Go straight to
gotchas.md
- Reviewing a script? Skim
bash-standards.md or powershell-standards.md for the compliance checklist, then error-handling.md for error-path quality
Quick Decision Trees
"I need to write a script"
What kind of script?
āā Bash (.sh)
ā āā Preamble and structure ā ./references/bash-standards.md
ā āā Error handling design ā ./references/error-handling.md
ā āā Signal handling / cleanup ā ./references/bash-standards.md
āā PowerShell (.ps1)
ā āā Preamble and structure ā ./references/powershell-standards.md
ā āā Native command error handling ā ./references/powershell-standards.md
ā āā Error handling design ā ./references/error-handling.md
āā Either language
āā Docker interaction ā ./references/error-handling.md
āā User-facing output ā ./references/error-handling.md
āā Cross-platform concerns ā ./references/gotchas.md
"I need to review a script"
Reviewing a script?
āā Bash compliance check
ā āā Preamble correct? ā ./references/bash-standards.md
ā āā Quoting discipline? ā ./references/bash-standards.md
ā āā ShellCheck clean? ā ./references/bash-standards.md
ā āā Error paths robust? ā ./references/error-handling.md
āā PowerShell compliance check
ā āā Preamble correct? ā ./references/powershell-standards.md
ā āā Native command handling? ā ./references/powershell-standards.md
ā āā PSScriptAnalyzer clean? ā ./references/powershell-standards.md
ā āā Error paths robust? ā ./references/error-handling.md
āā Either language
āā Exit code conventions? ā ./references/error-handling.md
āā Known gotchas present? ā ./references/gotchas.md
"Something is broken"
Script behaving unexpectedly?
āā Bash
ā āā Exit code masked ā ./references/gotchas.md (local var=$(cmd))
ā āā Variable empty/unset ā ./references/bash-standards.md (nounset)
ā āā Pipeline hiding failure ā ./references/bash-standards.md (pipefail)
ā āā cd went to wrong dir ā ./references/gotchas.md (cd without || exit)
āā PowerShell
ā āā Native command error ignored ā ./references/gotchas.md ($LASTEXITCODE)
ā āā Unexpected return value ā ./references/gotchas.md (implicit returns)
ā āā $null in ForEach loop ā ./references/gotchas.md
ā āā Validation not firing ā ./references/gotchas.md (omitted params)
ā āā irm | iex fails with BOM error ā ./references/gotchas.md (UTF-8 BOM)
āā Cross-platform
āā Env var case mismatch ā ./references/gotchas.md
āā Aliases missing ā ./references/gotchas.md
āā Exit code truncated ā ./references/gotchas.md
"I need to set up tests"
Testing shell scripts?
āā Bash testing
ā āā BATS setup ā ./references/testing.md
ā āā Mocking Docker ā ./references/testing.md
ā āā What to test ā ./references/testing.md
āā PowerShell testing
ā āā Pester setup ā ./references/testing.md
ā āā Mocking native commands ā ./references/testing.md
ā āā What to test ā ./references/testing.md
āā CI integration
āā GitHub Actions matrix ā ./references/testing.md
āā Lint-only vs full test ā ./references/testing.md
āā Path filtering ā ./references/testing.md
DAAF Script Conventions (Quick Reference)
Existing patterns in DAAF scripts that this skill codifies:
| Convention | Description | Example |
|---|
| Strict preamble | set -euo pipefail (Bash) / $ErrorActionPreference = 'Stop' (PS) | Every script, first lines |
| Numbered progress | [1/4] Checking prerequisites... | All multi-step scripts |
DAAF_NESTED flag | Suppress pause-before-exit when scripts compose | [ "${DAAF_NESTED:-}" = "1" ] && exit $ec |
| ERR trap pattern | Catch unexpected failures, explain recovery | trap 'echo "ERROR: ..."; exit 1' ERR |
| Preflight checks | Validate all dependencies before any mutation | command -v docker before Docker ops |
| Idempotent design | Check for prior state before acting | [ -f "$BACKUP" ] && echo "Already backed up" |
| Fail-closed hooks | Security hooks block on uncertainty | trap ... ERR; exit 2 |
| Backup before destroy | Copy before overwriting | cp -r "$TARGET" "$TARGET.bak" |
Bash Compliance Checklist (Summary)
| # | Requirement | Quick Check |
|---|
| 1 | #!/usr/bin/env bash shebang | First line |
| 2 | set -euo pipefail | Second line |
| 3 | All variables quoted | "$var", "$(cmd)" |
| 4 | local separate from $(cmd) | local x; x=$(cmd) |
| 5 | No eval, no backticks | Grep for both |
| 6 | trap cleanup EXIT for temp files | After variable declarations |
| 7 | ShellCheck clean | shellcheck -x -S warning |
| 8 | Errors to stderr with action guidance | echo "ERROR: ..." >&2 |
PowerShell Compliance Checklist (Summary)
| # | Requirement | Quick Check |
|---|
| 1 | $ErrorActionPreference = 'Stop' | First line |
| 2 | Set-StrictMode -Version 3.0 | Second line |
| 3 | $LASTEXITCODE checked after every native command | After docker, git, etc. |
| 4 | [CmdletBinding()] on functions | Function declarations |
| 5 | $null = expr not | Out-Null | Performance |
| 6 | No reliance on $? for native commands | Grep for $? near docker/git |
| 7 | PSScriptAnalyzer clean | Invoke-ScriptAnalyzer |
| 8 | Errors via Write-Error with guidance | Error output |
| 9 | ASCII-only content (no BOM) | file script.ps1 reports "ASCII text" |
| 10 | No interactive native commands in expression-context function calls | No if (Fn), $x = Fn for functions with docker exec, ssh, etc. |
Exit Code Conventions
| Code | Meaning | Used By |
|---|
| 0 | Success | All scripts |
| 1 | General error | All scripts |
| 2 | Blocked (hook convention) | .claude/hooks/*.sh |
| 10-19 | Docker failures | Docker lifecycle scripts |
| 20-29 | Configuration errors | Setup/config scripts |
| 30-39 | Dependency errors | Preflight validation scripts |
Topic Index
| Topic | Reference File |
|---|
| Bash shebang and preamble | ./references/bash-standards.md |
| Bash quoting rules | ./references/bash-standards.md |
| Bash variable handling | ./references/bash-standards.md |
| ShellCheck integration | ./references/bash-standards.md |
| Bash signal handling and cleanup | ./references/bash-standards.md |
| Bash never-do list | ./references/bash-standards.md |
| PowerShell preamble | ./references/powershell-standards.md |
| PowerShell ASCII-only encoding | ./references/powershell-standards.md |
| PowerShell dual error system | ./references/powershell-standards.md |
| PowerShell defensive coding | ./references/powershell-standards.md |
| PowerShell output streams | ./references/powershell-standards.md |
| PSScriptAnalyzer | ./references/powershell-standards.md |
| Fail-closed principle | ./references/error-handling.md |
| User-facing output formatting | ./references/error-handling.md |
| Exit code conventions | ./references/error-handling.md |
| Docker error handling | ./references/error-handling.md |
| Dependency validation | ./references/error-handling.md |
| NO_COLOR and TTY detection | ./references/error-handling.md |
| BATS test framework | ./references/testing.md |
| Pester test framework | ./references/testing.md |
| CI workflow setup | ./references/testing.md |
| Docker mocking strategies | ./references/testing.md |
| Test taxonomy (lint/unit/smoke/integration) | ./references/testing.md |
| What to test and what to skip | ./references/testing.md |
| Bash exit code masking | ./references/gotchas.md |
| Bash set -e edge cases | ./references/gotchas.md |
PowerShell exit in dot-sourced functions | ./references/gotchas.md |
| PowerShell $LASTEXITCODE vs $? | ./references/gotchas.md |
| PowerShell UTF-8 BOM breaks iex | ./references/gotchas.md |
| PowerShell implicit returns | ./references/gotchas.md |
| PowerShell $null pipeline behavior | ./references/gotchas.md |
| Cross-platform env var casing | ./references/gotchas.md |
| Cross-platform alias differences | ./references/gotchas.md |
| Cross-platform exit code truncation | ./references/gotchas.md |
| Cross-platform path separators | ./references/gotchas.md |