baphuongna/pi-crew/safe-bash

Claude Code and agent skill by baphuongna/pi-crew

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Safe shell-command workflow. When NOT to use: subprocess orchestration (use child-pi-spawning); destructive operations without sandbox (use ownership-session-security).

Install

npx vskill@latest install baphuongna/pi-crew/safe-bash

SKILL.md

safe-bash

Use this skill whenever a task may execute shell commands. This skill covers cross-platform shell safety, destructive action confirmation, and Windows-specific patterns.

Classification

Every shell command is either read-only or mutating. Always report which it is.

Read-only commands (safe)
bash
pwd # print working directory
ls -la # list files
find . -name "*.ts" | head -20 # search without writing
rg "pattern" --type ts | head -20 # ripgrep without write
git status # inspect state
git log --oneline -5 # recent commits
git diff --staged # staged changes
npm view <pkg> # query registry (no install)
npx tsc --noEmit # typecheck (no write)
node -e "console.log(process.version)" # inspect version
Mutating commands (require confirmation)
bash
npm install # changes node_modules
git commit # creates new commit
git push # publishes to remote
rm -rf <path> # DESTRUCTIVE
git reset --hard # rewrites history
npm publish # publishes to registry

Cross-Platform Considerations

Windows vs Unix paths
typescript
// ❌ Never hardcode paths with forward slashes on Windows
const path = "D:/project/src/file.ts";
// ✅ Use path.join() or Node's path module
import * as path from "path";
const filePath = path.join(cwd, "src", "file.ts");
// ✅ Or use forward slashes that work on both
const filePath = "src/file.ts"; // relative paths work on both
argv vs cmd /c
typescript
// ✅ Preferred on Windows: argv-based execution (no shell)
import { spawn } from "child_process";
spawn("node", ["--version"], { stdio: "pipe" });
// ✅ If shell needed: use cmd /c explicitly
spawn("cmd", ["/c", "dir /b"], { stdio: "pipe" });
// ❌ Don't use cmd /c with complex commands as single string
spawn("cmd", ["/c", "node --version && npm test"], { stdio: "pipe" });
Package manager detection
typescript
// Detect npm vs pnpm vs yarn
function detectPackageManager(cwd: string): "npm" | "pnpm" | "yarn" | "unknown" {
if (fs.existsSync(path.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
if (fs.existsSync(path.join(cwd, "yarn.lock"))) return "yarn";
return "npm";
}

Heredoc and Quoting Gotchas

Quoting variables in commands
bash
# ❌ Unsafe: variable expansion without quoting
node -e "console.log('$PATH')" # breaks on spaces
# ✅ Safe: escape single quotes in the string
node -e "console.log(process.env.PATH)" # use env, not shell var
# ✅ For file paths with spaces
ls "D:/my project/src"
Heredoc in scripts
bash
# ❌ Heredoc inside double quotes expands variables
cat << EOF
HOME is $HOME
EOF
# ✅ Use single quotes to prevent expansion
cat << 'EOF'
HOME is $HOME
EOF

Timeout and Background Execution

Timeout long-running commands
bash
# Linux/macOS: use timeout command
timeout 30 npm test # kill after 30 seconds
# Node.js: use AbortSignal
const controller = new AbortController();
setTimeout(() => controller.abort(), 30_000);
spawn("npm", ["test"], { signal: controller.signal });
# Windows: use /wait flag
start /wait cmd /c "npm test"
Background vs foreground
bash
# Background: run and forget (no output capture)
npm test &
# Foreground with timeout
timeout 60 npm test || echo "Timed out or failed"

Signal Handling

SIGTERM vs SIGKILL
SignalEffectUse case
SIGTERM (15)Graceful termination requestNormal shutdown
SIGKILL (9)Immediate forced terminationUnresponsive process
SIGINT (2)Interrupt (Ctrl+C)User cancel
bash
# Graceful: request termination
kill -15 <pid> # or: kill <pid>
# Force: immediate termination
kill -9 <pid> # or: kill -SIGKILL <pid>
# On Windows (cmd):
taskkill /pid <pid> /t /f # /t=tree, /f=force
Child process inheritance

When spawning subprocesses, child processes inherit the parent's signal handlers. Use signal: controller.signal in Node.js to give the child its own abort signal.

Sudo and Interactive Prompts

Detecting interactive prompts
bash
# Check if stdin is a terminal
[ -t 0 ] && echo "Interactive" || echo "Non-interactive"
Avoiding sudo prompts in scripts
bash
# ❌ This will hang waiting for password
npm install -g typescript
# ✅ Use expect or non-interactive mode
sudo npm install -g typescript 2>/dev/null # ignores prompt
NPM_CONFIG_INTERACTIVE=false npm install -g typescript

Error Trapping

set -e and set -o pipefail
bash
#!/bin/bash
set -e # Exit immediately on error
set -o pipefail # Pipeline fails if any command fails
# Good for CI/CD scripts
npm test
Capture and handle errors
bash
# Capture exit code
npm test || {
echo "Tests failed with exit code $?"
exit 1
}
# Check for command existence
command -v npm >/dev/null 2>&1 || { echo "npm not found"; exit 1; }

ANSI Color Code Stripping

For log parsing, strip ANSI escape codes:

typescript
// Strip ANSI color codes from output
function stripAnsi(text: string): string {
return text.replace(/\x1B\[[0-9;]*[mK]/g, "");
}
// Usage
const output = stripAnsi(child.stdout);
const hasFailure = output.includes("FAIL");

Or via shell:

bash
# Strip ANSI codes using sed
npm test 2>&1 | sed 's/\x1B\[[0-9;]*[mK]//g'

Node.js vs Binary Detection

typescript
// Detect node executable
import { execSync } from "child_process";
function findNode(): string {
// Try common paths
for (const candidate of [
process.execPath,
"node",
"C:\\Program Files\\nodejs\\node.exe",
"/usr/local/bin/node",
]) {
try {
execSync(`"${candidate}" --version`, { stdio: "ignore" });
return candidate;
} catch { /* continue */ }
}
return "node"; // fallback
}

Destructive Action Confirmation

Never execute destructive commands without explicit confirmation:

CommandRiskConfirmation needed
rm -rf <path>Permanent data loss"Type the path to confirm"
git reset --hardUndo all changes"Confirm with: YES"
git clean -fdRemove untracked files"Confirm with: YES"
npm publishPublic package"Confirm version X.Y.Z"

Confirmation pattern:

bash
# Require user to type the exact path
read -p "Type the directory path to confirm deletion: " CONFIRM
if [ "$CONFIRM" = "$TARGET_PATH" ]; then
rm -rf "$TARGET_PATH"
else
echo "Aborted: paths do not match"
fi

Enforcement — Safe Bash Gate

Before executing shell commands, verify:

  • [ ] Command classified as read-only or mutating (report which)
  • [ ] Mutating/destructive commands have explicit confirmation before execution
  • [ ] Paths use platform-safe construction (path.join, not hardcoded forward slashes)
  • [ ] Timeout set for long-running commands (prevent blocking)
  • [ ] Exit codes checked and errors handled appropriately
  • [ ] Secrets not passed in command-line args (use environment variables)

If ANY answer is NO → Stop. Classify and protect before executing.

Anti-patterns

  • `rm -rf` without path validation: Always double-check the path before rm -rf
  • Blocking on subprocess: Always use async spawn with timeout
  • Ignoring exit codes: Check $? or capture exitCode from Node.js spawn
  • Leaking secrets in args: Use environment variables instead of command-line args
  • Not handling Windows spaces: Test on Windows before assuming paths work
  • Background process zombie: Always handle process exit or store the pid for cleanup

Source patterns

  • src/utils/resolve-shell.ts — cross-platform shell detection
  • src/runtime/child-pi.ts — spawn, killProcessPid, signal handling
  • src/worktree/worktree-manager.ts — git commands via execFileSync
  • src/config/defaults.ts — platform detection

Verification

bash
cd pi-crew
# Check exit code handling
node -e "const {spawnSync}=require('child_process'); console.log(spawnSync('false').status)"
# Test ANSI stripping
node -e "console.log('\x1B[32mgreen\x1B[0m'.replace(/\x1B\[[0-9;]*[mK]/g,''))"
# Verify cross-platform path
node -e "const p=require('path'); console.log(p.join('D:\\\\','project','src'))"
# TypeScript
npx tsc --noEmit

Security

  • Security scanPassed, 90 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

7-day trend score
0

Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/baphuongna/pi-crew/safe-bash/badge)](https://verified-skill.com/skills/baphuongna/pi-crew/safe-bash)

Something wrong with this skill or its page? Tell us.