description: Idiomatic shell development for POSIX sh, Bash, Zsh, Fish, hooks, CI
shell steps, and scriptable CLI glue. Use when writing or changing .sh, .bash,
.zsh, .fish, .bats, shell functions, shell pipelines, or command-runner recipes.
Emphasizes portability, quoting, safe filesystem/process handling, non-TUI CLI tools,
ShellCheck, shfmt, Bats, and ShellSpec. NOT for Python, TypeScript, Go, web code,
or infrastructure operations.
name: writing-shell
Shell Development
Scope
- Use for shell scripts, hooks, CI shell blocks, command pipelines, and local automation glue.
- Do not use for cloud, Kubernetes, Terraform, host, or network operations; use
operating-infra. - Do not use for application logic that belongs in Python, Go, TypeScript, or another project language.
Read references
- Read patterns.md before non-trivial scripts or pipelines.
- Read tools.md when choosing external CLI tools or parsing structured data.
- Read testing.md before adding or changing shell tests or quality gates.
Defaults
- Follow the existing shebang, shell, style, and project tooling first.
- For new portable scripts, use POSIX
shwhen the logic is simple; use Bash when arrays,pipefail, regex, or richer functions are needed. - Use Zsh or Fish only for existing files or explicit user intent. Keep Fish/Zsh config separate from portable scripts.
- Do not rely on the agent's current shell. Put the intended shell in the shebang or invoke it explicitly in tests.
- Prefer small shell scripts that call stable tools. Move complex data modeling or business logic to a real language.
Core rules
- Quote expansions unless word splitting is intentional and documented by structure.
- Avoid
eval,curl | sh, parsingls, unguarded globbing, and unsaferm/mv/cppaths. - Use arrays for arguments in Bash; use newline/NUL-safe loops for filenames.
- Use
mktempplus cleanup traps for temporary files and directories. - Check required external commands when a script depends on them. Do not install tools silently.
- Account for macOS/BSD versus GNU flag differences when writing portable scripts.
- Prefer machine-readable output from tools, then parse it with structured parsers.
- Use
looking-up-docsfor exact external CLI flags, syntax, or version behavior; do not guess from memory.
Verification
Run the project-configured shell gates. Prefer:
- formatting:
shfmt - linting:
shellcheck;checkbashismsfor POSIXsh - tests: Bats for Bash-heavy projects; ShellSpec for POSIX or multi-shell behavior
- security/policy: Semgrep shell rules when the script handles secrets, downloads, deletion, or user-controlled input
If a tool is unavailable or unconfigured, state the gap and run the closest available check. If a check fails, quote the diagnostic, fix the cause, and rerun the relevant check.
Final response
Include:
- changed files
- shell target used: POSIX sh, Bash, Zsh, or Fish
- checks run and results
- checks skipped with reasons
- remaining portability or safety risks