Bash Expert
Caution
Ad-hoc bash is the leading cause of deploy incidents. Missing set -euo pipefail, unquoted variables, hardcoded /usr/local paths — each one is a time bomb. The agent writes scripts that are correct by construction, not by luck.
Tip
Trigger by describing the script you need. “create a setup script for my plugin”, “bash script to check homebrew services”, “install script for macOS and Linux” — the agent picks the right template, adds error handling, and validates syntax before handing back the file.
Quick reference
| Field | Value |
|---|---|
| Model | inherit — runs on the session’s model |
| Tools | Read, Write, Edit, Glob, Grep, Bash, WebFetch |
| Triggers | ”create script”, “bash script”, “shell script” |
| Output | .sh file + bash -n + ShellCheck report |
Scope guard
Bash Expert sizes the task before writing. One bounded unit = one deliverable, roughly 5 files, roughly 10 steps.
| Situation | What the agent does |
|---|---|
| Brief fits one bounded unit | Starts immediately |
| Brief exceeds ~5 files / ~10 steps, or bundles several independent deliverables | Stops before starting, returns a split proposal: 2-N bounded subtasks, each with scope and a suggested owner |
| Scope grows mid-flight | Stops at the next clean boundary, reports done / remaining / how to split |
| Brief is missing GOAL, SCOPE, CONTEXT, CONSUMER or acceptance | States the assumption explicitly in the report, or asks once — never invents scope |
“Write the whole CI toolchain” gets a split proposal. “Write the install script for brewtools” gets a script.
Tip
Got a split proposal instead of a script? That is the guard working. Pick one script from the proposal and re-send it, or spawn the subtasks as parallel agents in a single message.
When to use
- Plugin lifecycle scripts — setup, install, teardown, version-bump for brewcode/brewtools/brewui/brewdoc
- CI helper scripts — health checks, service validation, environment bootstrap
- Cross-platform portability — script must run on both macOS (ARM + Intel) and Linux without modification
- Structured output — script prints markdown tables or phase headers consumed by Claude Code skills
- Idempotent installers — safe to re-run; checks state before mutating
Examples
# Natural language triggers
"create a setup script for the brewtools plugin"
"bash script to check if all homebrew services are running"
"write an install script that works on macOS and Linux"
# Multi-mode dispatch
"write a multi-mode script with status/install/help commands"
# Plugin-aware paths resolve via ${CLAUDE_PLUGIN_ROOT}
"create a version-bump script for the plugin"
Flow
- Analyze the request
Reads existing scripts in the repo (Glob + Grep) to match conventions. Identifies target platform, required commands, and expected output format before writing a single line.
- Choose a template
Minimal (single-purpose, ≤20 lines) or full multi-mode dispatch (`CMD="${1:-help}"` +
caseblock). Plugin scripts always getSCRIPT_DIRself-location and correct plugin-root resolution. - Implement
Writes the script with
set -euo pipefail, quoted variables,trap cleanup EXITwhere needed, and status symbols (✅ ❌ ⚠️) in output. macOS/Linux divergences handled via platform detection, not hardcoded paths. - Validate
Runs
bash -n script.sh(syntax check) andshellcheck script.sh(static analysis). Fixes all ShellCheck warnings before reporting. - Report
Prints a structured summary: file path, purpose, platform, and a checklist of verified properties. You get a ready-to-run script, not a draft.
Internals — patterns, templates, and platform handling
Conventions
| Pattern | Example | Use |
|---|---|---|
| Strict mode | set -euo pipefail | Every script, by default |
| Cleanup trap | trap cleanup EXIT | Temp files, locks, other resources |
| Required var | ${VAR:?error msg} | Mandatory input |
| Soft failure | cmd || echo "⚠️ warning" | Optional steps |
Mode detection
ARGS_LOWER=$(echo "${1:-}" | tr '[:upper:]' '[:lower:]')
[[ "$ARGS_LOWER" =~ (install|setup|init) ]] && MODE="install"
[[ "$ARGS_LOWER" =~ (update|upgrade) ]] && MODE="update"
[[ -z "$ARGS_LOWER" ]] && MODE="default"Minimal template
#!/bin/bash
set -euo pipefail
ARG="${1:-}"
[[ -z "$ARG" ]] && { echo "Usage: script.sh <arg>"; exit 1; }
echo "Processing: $ARG"
echo "✅ Done"macOS vs Linux divergences
| Feature | macOS | Linux |
|---|---|---|
| Brew prefix | /opt/homebrew (ARM), /usr/local (Intel) | /home/linuxbrew/.linuxbrew |
| timeout | gtimeout (coreutils) | timeout |
| sed in-place | sed -i '' | sed -i |
| readlink | greadlink -f | readlink -f |
Always derive prefix via $(brew --prefix) — never hardcode.
Structured output
| Element | Pattern |
|---|---|
| Status symbols | ✅ success · ❌ error · ⚠️ warning · ⏭️ skipped · 🔄 updated |
| Markdown table | echo "| Component | Status |" then the separator row, then data rows |
| Phase header | echo "=== Phase 1: Scanning ===" && echo "" |
JSON parsing fallback chain
jq -r '.key' file.jsonpython3 -c "import json,sys;print(json.load(sys.stdin)['key'])"grep -oP '"key":\s*"\K[^"]+' file.json
Plugin path variables
| Variable | Available in |
|---|---|
$CLAUDE_PLUGIN_ROOT | Hooks only |
${CLAUDE_SKILL_DIR} | Skills (string substitution) |
${CLAUDE_PLUGIN_ROOT} | Agents (native substitution in agent .md at Task spawn) |
Anti-patterns
| Avoid | Prefer |
|---|---|
[ $VAR ] | [[ -n "$VAR" ]] |
cat file | grep | grep X file |
ls | while read | find -exec or glob |
cd dir; cmd; cd - | (cd dir && cmd) |
echo $VAR | echo "$VAR" |
if [ $? -eq 0 ] | if cmd; then |
/usr/local hardcoded | $(brew --prefix) |
Delivery checklist
| # | Check |
|---|---|
| 1 | #!/bin/bash shebang |
| 2 | set -euo pipefail |
| 3 | Usage header comment |
| 4 | shellcheck clean |
| 5 | chmod +x applied |
| 6 | bash -n passes |
| 7 | help subcommand works |
| 8 | Error paths tested |
| 9 | Idempotent — safe re-run |
Return Contract
Verdict first, <=30 lines, path:line. No script bodies, no ShellCheck transcripts, no smoke-run output, no preamble — one block per script, nothing else (the format is in Flow step 5 above). Failures return the check that failed plus the offending path:line, never the full output; long logs and full ShellCheck runs go to .claude/reports/<YYYYMMDD-HHMMSS>_bash-expert/, path only.
/brewtools:agent-return-setup enforces this at ~1000 / ~2500 est-tokens when installed; the contract itself ships unconditionally.
hook-creator agent
Builds Claude Code hooks — pairs with bash-expert when a hook shells out.
GitHub source
Agent definition, system prompt, and tool configuration.
Brewcode overview
All brewcode skills and agents in one place.
Updating plugins
/brewtools:plugin-update to check and update the brewcode plugin suite in one command.
See the FAQ for details.