shell-review
Audits shell scripts for correctness, portability, and common pitfalls Skill: shell-review Owner: athola Summary: Audits shell scripts for correctness, portability, and common pitfalls Tags: latest:1.9.19 Version history: v1.9.19 | 2026-08-26T13:19:27.339Z | user Release v1.9.19 v1.9.17 | 2026-07-30T05:39:38.105Z | user Release v1.9.17 v1.9.16 | 2026-07-14T19:56:22.538Z | user Release v1.9.16 v1.9.14 | 2026-06-30T18:04:36.162Z | user Release v1.9.14 v1.9.13 | 2026-06-27T16:22:33.599Z |
Rank
62
Safety
84
Downloads
1.6k
Updated
Oct 10, 2026
Version
1.9.19
Source
CLAWHUB
About
What it does, and when to use it.
Capability contract not published. No trust telemetry is available yet. 1.6K downloads reported by the source. Last updated 10/10/2026.
Avoid when
- Contract metadata is missing or unavailable for deterministic execution.
Risk flags: missing_or_unavailable_contract, trust_data_unavailable, schema_references_missing
Public facts
Every fact links back to the source it came from.
- Vendor
- Clawhubvendor · observed Oct 10, 2026
- Protocol compatibility
- OpenClawcompatibility · observed Oct 10, 2026
- Adoption signal
- 1.6K downloadsadoption · observed Oct 10, 2026
- Latest release
- 1.9.19release · observed Aug 26, 2026
- Handshake status
- UNKNOWNsecurity
Install and run
Setup complexity: low.
clawhub skill install s17emme0e2m3cpf7k2jvp3a84984b8z9:nm-pensive-shell-review- Setup complexity is classified as HIGH. You must provision dedicated cloud infrastructure or an isolated VM. Do not run this directly on your local workstation.
- Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data.
Contract: missing
curl -s "https://www.xpersona.co/api/v1/agents/clawhub-athola-nm-pensive-shell-review/snapshot"
Documentation
CLAWHUB
145,036 characters of source documentation, loaded on request.
Extracted files
5 files captured from the source.
SKILL.md
---
name: shell-review
description: Audits shell scripts for correctness, portability, and common pitfalls
version: 1.9.8
triggers:
- shell
- bash
- posix
- scripting
- ci
- hooks
- reviewing shell scripts or before committing shell changes
metadata: {"openclaw": {"homepage": "https://github.com/athola/claude-night-market/tree/master/plugins/pensive", "emoji": "\ud83e\udd9e", "requires": {"config": ["night-market.pensive:shared", "night-market.imbue:proof-of-work"]}}}
source: claude-night-market
source_plugin: pensive
---
> **Night Market Skill** — ported from [claude-night-market/pensive](https://github.com/athola/claude-night-market/tree/master/plugins/pensive). For the full experience with agents, hooks, and commands, install the Claude Code plugin.
## Table of Contents
- [Quick Start](#quick-start)
- [When to Use](#when-to-use)
- [Required TodoWrite Items](#required-todowrite-items)
- [Workflow](#workflow)
- [Output Format](#output-format)
# Shell Script Review
Audit shell scripts for correctness, safety, and portability.
## Verification
After review, run `shellcheck <script>` to verify fixes address identified issues.
## Testing
Run `pytest plugins/pensive/tests/skills/test_shell_review.py -v` to validate review patterns.
## Quick Start
```bash
/shell-review path/to/script.sh
```
## When To Use
- CI/CD pipeline scripts
- Git hook scripts
- Wrapper scripts (run-*.sh)
- Build automation scripts
- Pre-commit hook implementations
## When NOT To Use
- Non-shell scripts (Python, JS, etc.)
- One-liner commands that don't need review
## Required TodoWrite Items
1. `shell-review:context-mapped`
2. `shell-review:exit-codes-checked`
3. `shell-review:portability-checked`
4. `shell-review:safety-patterns-verified`
5. `shell-review:structure-checked`
6. `shell-review:evidence-logged`
## Workflow
### Step 1: Map Context (`shell-review:context-mapped`)
Identify shell scripts:
```bash
# Find shell scripts
find . -not -path "*/.venv/*" -not -path "*/__pycache__/*" \
-not -path "*/node_modules/*" -not -path "*/.git/*" \
-name "*.sh" -type f | head -20
# Check shebangs
rg -l "^#!/" scripts/ hooks/ 2>/dev/null | head -10
# fallback: grep -l "^#!/" scripts/ hooks/ 2>/dev/null | head -10
```
Document:
- Script purpose and trigger context
- Integration points (make, pre-commit, CI)
- Expected inputs and outputs
### Step 2: Exit Code Audit (`shell-review:exit-codes-checked`)
@include modules/exit-codes.md
### Step 3: Portability Check (`shell-review:portability-checked`)
@include modules/portability.md
### Step 4: Safety Patterns (`shell-review:safety-patterns-verified`)
@include modules/safety-patterns.md
### Step 5: Structure Patterns (`shell-review:structure-checked`)
@include modules/structure-patterns.md
### Step 6: Evidence Log (`shell-review:evidence-logged`)
Use `imbue:proof-of-work` to record findings with file:line references.
Summarize:
- Critical issues (failures masked, security risks)
- Major issues (p_meta.json
{
"ownerId": "kn7d107jg9jv602h9ytsegydq184a42s",
"slug": "nm-pensive-shell-review",
"version": "1.9.19",
"publishedAt": 1787750367339
}modules/exit-codes.md
---
parent_skill: pensive:shell-review
module: exit-codes
description: Exit code propagation patterns and pipeline pitfalls
tags: [exit-codes, pipelines, error-handling, pipefail]
---
# Exit Code Patterns
## Critical: Pipeline Exit Codes
The default bash behavior is that a pipeline's exit code equals the **last** command's exit code. This masks failures:
```bash
# BAD - grep always succeeds if it finds lines, hiding make failure
if (make typecheck 2>&1 | grep -v "^make\["); then
echo "Passed" # WRONG - runs even when make fails!
fi
```
### Fix 1: Use pipefail
```bash
set -o pipefail
# Now pipeline fails if ANY command fails
if make typecheck 2>&1 | grep -v "^make\["; then
echo "Passed"
fi
```
### Fix 2: Capture Output and Exit Code Separately
```bash
# Capture output, preserve exit code
local output
local exit_code=0
output=$(make typecheck 2>&1) || exit_code=$?
# Filter output for display
echo "$output" | grep -v "^make\[" || true
# Check actual exit code
if [ "$exit_code" -eq 0 ]; then
echo "Passed"
else
echo "Failed"
return 1
fi
```
### Fix 3: Use PIPESTATUS (Bash-specific)
```bash
make typecheck 2>&1 | grep -v "^make\["
if [ "${PIPESTATUS[0]}" -ne 0 ]; then
echo "Make failed"
exit 1
fi
```
## Detection Commands
Find pipeline patterns that may mask failures:
```bash
# Commands piped to grep/head/tail (common culprits)
grep -n "| grep" scripts/*.sh
grep -n "| head" scripts/*.sh
grep -n "| tail" scripts/*.sh
# Pipelines in if conditions
grep -n "if.*|" scripts/*.sh
# Subshells with pipelines
grep -n "\$(.*|" scripts/*.sh
```
## set -e Pitfalls
`set -e` (exit on error) has exceptions that can surprise:
```bash
set -e
# These do NOT trigger exit:
cmd || true # Explicit fallback
if cmd; then ... # Part of condition
cmd && other # Part of AND/OR list
while cmd; do ... # Loop condition
# This DOES trigger exit:
cmd # Standalone command that fails
```
## Subshell Exit Codes
```bash
# BAD - subshell exit code lost
(cd /tmp && failing_command)
echo "This runs even if failing_command failed"
# GOOD - check subshell result
if ! (cd /tmp && failing_command); then
echo "Failed"
exit 1
fi
# GOOD - use || to handle failure
(cd /tmp && failing_command) || { echo "Failed"; exit 1; }
```
## Common Patterns to Flag
| Pattern | Risk | Fix |
|---------|------|-----|
| `cmd \| grep` in `if` | Exit code from grep | pipefail or capture |
| `$(cmd \| filter)` | Exit code from filter | PIPESTATUS or capture |
| `cmd \| head -1` | Loses cmd failure | pipefail |
| `cmd 2>&1 \| tee log` | May hide failure | pipefail |
| `set -e` and pipes | Inconsistent behavior | Explicit checks |modules/portability.md
---
parent_skill: pensive:shell-review
module: portability
description: POSIX vs Bash compatibility and cross-platform considerations
tags: [posix, bash, portability, cross-platform]
---
# Shell Portability
## Shebang Lines
```bash
#!/bin/sh # POSIX shell (most portable)
#!/bin/bash # Bash (most features)
#!/usr/bin/env bash # Bash via env (handles non-standard paths)
```
If using Bash features, use `#!/usr/bin/env bash` for portability across systems where bash may not be at `/bin/bash`.
## Bash-Only Features
These require `#!/bin/bash` or `#!/usr/bin/env bash`:
| Feature | Bash | POSIX Alternative |
|---------|------|-------------------|
| `[[ ... ]]` | Yes | `[ ... ]` |
| `(( ... ))` | Yes | `$(( ... ))` or `[ ... ]` |
| Arrays | Yes | Use files or positional params |
| `${var:offset:len}` | Yes | `expr` or external tools |
| `${var//pat/rep}` | Yes | `sed` |
| `<<<` here-string | Yes | `echo "$var" \|` |
| `<(cmd)` process sub | Yes | Temp files or pipes |
| `source file` | Yes | `. file` |
| `function name { }` | Yes | `name() { }` |
| `local -n` nameref | Bash 4.3+ | Workarounds |
## Detection Commands
```bash
# Find Bash-isms in #!/bin/sh scripts
grep -l "^#!/bin/sh" scripts/*.sh | while read f; do
# Check for [[ ]]
grep -n "\[\[" "$f" && echo " ^ $f uses [[ ]]"
# Check for arrays
grep -n "=(" "$f" && echo " ^ $f uses arrays"
done
# Find all shebang types
grep -h "^#!" scripts/*.sh | sort -u
```
## Common Portability Fixes
### Test Brackets
```bash
# BAD - Bash only
if [[ -f "$file" && "$var" == "value" ]]; then
# GOOD - POSIX
if [ -f "$file" ] && [ "$var" = "value" ]; then
```
### String Comparison
```bash
# BAD - Bash only (== works but not standard)
if [ "$a" == "$b" ]; then
# GOOD - POSIX
if [ "$a" = "$b" ]; then
```
### Arithmetic
```bash
# BAD - Bash only
((count++))
if (( count > 10 )); then
# GOOD - POSIX
count=$((count + 1))
if [ "$count" -gt 10 ]; then
```
### Local Variables
```bash
# BAD - 'local' is not POSIX (but widely supported)
local var="value"
# GOOD - explicitly use in functions only, document assumption
# Most modern shells support 'local', acceptable if documented
```
## macOS vs Linux
```bash
# sed -i differs
# Linux: sed -i 's/a/b/' file
# macOS: sed -i '' 's/a/b/' file
# Portable approach
sed 's/a/b/' file > file.tmp && mv file.tmp file
# Or detect platform
case "$(uname -s)" in
Darwin*) SED_INPLACE="sed -i ''" ;;
*) SED_INPLACE="sed -i" ;;
esac
```
## Recommendation
1. Use `#!/usr/bin/env bash` and document Bash requirement
2. Or use `#!/bin/sh` and avoid ALL Bash-isms
3. Don't mix - pick one and be consistentmodules/safety-patterns.md
---
parent_skill: pensive:shell-review
module: safety-patterns
description: POSIX safety rules: no echo, braced vars, :? expansion, cd subshells
tags: [safety, posix, quoting, expansion, cd]
---
# Shell Safety Patterns
## No echo: use log() or printf
All output must go through `log()` from `scripts/logging.sh` or via
`printf(1)`. The only exception is `usage()` body lines (after
the first), where `printf` is used directly.
Detection:
```sh
# Bare echo calls in non-comment lines
rg -n '^\s*echo\s' scripts/ .githooks/ plugins/*/hooks/
# fallback: grep -rn '^\s*echo\s' scripts/ .githooks/
```
Fix: replace `echo "msg"` with `log "msg"` or `printf '%s\n' "msg"`.
## Braced variable references
Every variable reference must use the braced form `${VAR}`, not
bare `$VAR`. This avoids surprises with adjacent text and is
required for consistent ShellCheck compliance.
Detection:
```sh
rg -n '\$[A-Za-z_][A-Za-z_0-9]*[^}]' scripts/
```
Fix: `$VAR` → `${VAR}`, `$1` → `${1}`, `$@` → `"${@}"`.
## :? expansion instead of branching on unset
Never branch on an unset variable before triggering an exit-path.
Use `${VAR:?message}` so the shell emits the message and exits
immediately when the variable is unset or empty.
```sh
# Bad — branches on unset, then exits
if [ -z "${DIR}" ]; then
log 4 "DIR is unset"
exit 1
fi
# Good — parameter expansion handles it
process_dir "${DIR:?DIR must be set}"
```
Detection:
```sh
rg -n '\[ -z.*\$\{?\w' scripts/ # [ -z "$VAR" ] before exit
```
## cd inside a subshell
Every `cd` must be wrapped in a subshell so that the change of
directory does not persist and a failed `cd` cannot leave the
script in the wrong directory.
```sh
# Bad — cd leaks to caller scope; fails silently without set -e
cd "${build_dir}"
make clean
# Good — scoped and guarded
(cd "${build_dir:?No build dir}" && make clean)
```
Detection:
```sh
rg -n '^\s*cd\s+[^(]' scripts/ # cd not wrapped in (
```
## Source relative to script location
External files must be sourced relative to the script's own
location, not the caller's working directory.
```sh
# Bad — breaks when invoked from any other directory
. ./logging.sh
# Good — always resolves from the script's directory
MYDIR="${0%/*}"
. "${MYDIR%/}/logging.sh"
```
Use `${0%/*}` (POSIX parameter expansion) instead of `dirname "$0"`.
## No basename or dirname
Use POSIX parameter expansion instead of the external commands
`basename` and `dirname`.
| Command | Expansion |
|---------|-----------|
| `basename "$path"` | `"${path##*/}"` |
| `dirname "$path"` | `"${path%/*}"` |
| `basename "$path" .ext` | `f="${path##*/}"; "${f%.ext}"` |
Detection:
```sh
rg -n '\bbasename\b|\bdirname\b' scripts/
```
## Library loading check form
When a script must verify a library was sourced, use the canonical
`case` form, not `[ -z … ]` or `[ -n … ]`:
```sh
# Required form — distinguishes unset/empty/loaded
case "${__logging_loaded:-NULL}" in
1) : ;; # loaded
*) printf 'logging.sh not loaded\AionUi
Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!
activepieces
AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents
cherry-studio
AI productivity studio with smart chat, autonomous agents, and 300+ assistants.
CopilotKit
The Frontend for Agents & Generative UI. React + Angular
Machine-readable data
The same record, as JSON, for agents and crawlers.
{
"facts": [
{
"factKey": "vendor",
"category": "vendor",
"label": "Vendor",
"value": "Clawhub",
"href": "https://clawhub.ai/athola/skills/nm-pensive-shell-review",
"sourceUrl": "https://clawhub.ai/athola/skills/nm-pensive-shell-review",
"sourceType": "profile",
"confidence": "medium",
"observedAt": "2026-10-10T07:32:00.205Z",
"isPublic": true
},
{
"factKey": "protocols",
"category": "compatibility",
"label": "Protocol compatibility",
"value": "OpenClaw",
"href": "https://www.xpersona.co/api/v1/agents/clawhub-athola-nm-pensive-shell-review/contract",
"sourceUrl": "https://www.xpersona.co/api/v1/agents/clawhub-athola-nm-pensive-shell-review/contract",
"sourceType": "contract",
"confidence": "medium",
"observedAt": "2026-10-10T07:32:00.205Z",
"isPublic": true
},
{
"factKey": "traction",
"category": "adoption",
"label": "Adoption signal",
"value": "1.6K downloads",
"href": "https://clawhub.ai/athola/nm-pensive-shell-review",
"sourceUrl": "https://clawhub.ai/athola/nm-pensive-shell-review",
"sourceType": "profile",
"confidence": "medium",
"observedAt": "2026-10-10T07:32:00.205Z",
"isPublic": true
},
{
"factKey": "latest_release",
"category": "release",
"label": "Latest release",
"value": "1.9.19",
"href": "https://clawhub.ai/athola/nm-pensive-shell-review",
"sourceUrl": "https://clawhub.ai/athola/nm-pensive-shell-review",
"sourceType": "release",
"confidence": "medium",
"observedAt": "2026-08-26T13:19:27.339Z",
"isPublic": true
},
{
"factKey": "handshake_status",
"category": "security",
"label": "Handshake status",
"value": "UNKNOWN",
"href": "https://www.xpersona.co/api/v1/agents/clawhub-athola-nm-pensive-shell-review/trust",
"sourceUrl": "https://www.xpersona.co/api/v1/agents/clawhub-athola-nm-pensive-shell-review/trust",
"sourceType": "trust",
"confidence": "medium",
"observedAt": null,
"isPublic": true
}
],
"events": [
{
"eventType": "release",
"title": "Release 1.9.19",
"description": "Release v1.9.19",
"href": "https://clawhub.ai/athola/nm-pensive-shell-review",
"sourceUrl": "https://clawhub.ai/athola/nm-pensive-shell-review",
"sourceType": "release",
"confidence": "medium",
"observedAt": "2026-08-26T13:19:27.339Z",
"isPublic": true
}
]
}Record generated Oct 10, 2026.
