agentleFS
Evan-DaruwallaEvan-Daruwalla/claude-skill-suite/shell-portability/SKILL.md

shell-portability

Skill0 starsChanged 45 days agoMITView on GitHub

Read-only scan for cross-shell traps with PS-5.1-safe fixes: && and ||, PS7-only syntax, blocking prompts, missing -Encoding, bash-isms in .ps1. check "<cmd>" tests one command. Use when: "will this run on PowerShell 5.1", "lint my shell scripts".

  • Commits and pushes

The file

We split this skill into the rules it gives an agent

2 rules. About 0 are common, 1 is distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Read-only; it never writes outside its own canary temp dir.

    line 17
  2. Very specific:

    Read-only — writes nothing except inside a throwaway temp dir during --canary.

    line 131

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

shell-portability — cross-shell syntax trap scanner

The engine is shell-portability.js (portable Node, zero deps). It is the proactive counterpart to a reactive shell-troubleshooting runbook (that runbook diagnoses a script that already broke; this scans the source and flags the same documented traps before they reach the shell) — with file:line, why it breaks on a Windows machine, and the PowerShell-5.1-safe alternative. Read-only; it never writes outside its own canary temp dir.

Scope is syntax and semantics only. Encoding and filename quirks (non-ASCII bytes that corrupt a .bat parse, UTF-16 BOMs, builtin-shadowing stray files) are path-quirk-audit's job — this scanner deliberately does not duplicate them, and it skips .bat files entirely.

What it flags

.ps1 / .psm1 — the target here is PowerShell 5.1 (the common Windows default, not PS7):

TrapWhy it breaksPS5.1-safe fix
&& / ||no pipeline-chain operators — parser errorA; if ($?) { B } / A; if (-not $?) { B }
?: ternaryPS7-onlyif/else
?. / ?[]null-conditional, PS7-onlyguard with if ($null -ne $x)
?? / ??=null-coalescing, PS7-onlyif ($null -eq $x) { ... }
Read-Host / pause / Out-GridViewblock a non-interactive / scheduled runtake input as a param / env / file
Set-Content/Add-Content/Out-File w/o -EncodingANSI/UTF-16 default corrupts UTF-8 for the next readeradd -Encoding utf8
bash-style NAME=value / export NAME=valuePS can't assign to a bareword; export isn't a cmdlet$name = value / $env:NAME = 'value'
a parameter 5.1 lacks: ConvertFrom-SecureString -AsPlainText, Get-Content/Set-Content -AsByteStream, ForEach-Object -Parallel, ConvertFrom-Json -AsHashtable, ConvertTo-Json -AsArray, Invoke-WebRequest/Invoke-RestMethod -SkipCertificateCheckparameter binding error (measured absent on 5.1, 2026-09-28)per-parameter fix in the report

Any file, and check: the payload of powershell -Command "..." / pwsh -c '...' is scanned as PowerShell. String masking used to hide it, so a trap wrapped in -Command reported clean.

.sh / .bash — PowerShell-isms leaking into a POSIX script:

TrapWhy it breaksPOSIX fix
$env:NAMEbash has no $env: namespace$NAME / ${NAME}, set with export
Verb-Noun cmdlet (Get-ChildItem, Set-Content, ...)PowerShell cmdlet, not a bash commandPOSIX equivalent (ls/find, printf > file)

Commands

node shell-portability.js scan <path> [<path>...]
node shell-portability.js check "<command>" [--sh]
node shell-portability.js --canary
node shell-portability.js --help
  • scan recurses any files or directories given (skips .git, node_modules, .golden, graphify-out), reads every .ps1/.psm1/.sh/.bash file, and prints one block per finding:

    path\to\deploy.ps1:12: [chain-and-or] PS 5.1 has no && / || pipeline-chain operators (parser error)
        fix: A; if ($?) { B }  (and)   /   A; if (-not $?) { B }  (or)
        > git pull && npm run build

    Exit 1 if anything is flagged, 0 if clean.

  • check runs the same rule table over ONE command string instead of a file. Use it before handing a command to someone to run. Defaults to the PowerShell 5.1 dialect; --sh checks it as POSIX instead. Same exit codes.

    $ node shell-portability.js check 'cd "D:/repo" && npm run build'
    <command>:1: [chain-and-or] PS 5.1 has no && / || pipeline-chain operators (parser error)
        fix: A; if ($?) { B }  (and)   /   A; if (-not $?) { B }  (or)
        > cd "D:/repo" && npm run build

    ALWAYS QUOTE the command. Unquoted, your own shell eats the && before Node sees it, so only the first half is scanned and it reports clean — a false negative, the worst outcome for a gate. The clean line echoes exactly what was scanned (clean: no PowerShell 5.1 traps in: cd D:/repo) so that truncation is visible rather than silent.

Why check exists

scan only reads files. A command written into a chat reply, a README, or a runbook never reaches the scanner's input surface — which is how a cd X && git push gets handed to a PowerShell 5.1 user with the rule that would catch it sitting right there, having nothing to run against. check closes that gap by making a bare string checkable.

Suppression

A trailing # portability-ok comment silences every finding on that line — use it for a deliberate exception (e.g. a string that merely contains &&, or a script that is PS7-only on purpose):

$result = git pull && git push   # portability-ok  (PS7 CI runner only)

Examples

  • Guard a scheduled job's script before it ships (a monthly rebalance job runs as a Windows scheduled task — a Read-Host or a && would hang or parser-error unattended): node shell-portability.js scan /path/to/scripts — catches any interactive prompt or PS7-ism before the scheduled run hits it.
  • Check a helper .ps1 writes UTF-8 for the next tool (Set-Content's ANSI default is a well-known trap): the scanner flags every Set-Content/Out-File missing -Encoding utf8.
  • Scan a .sh you cross-wrote in a PowerShell headspace: catches a stray $env:PATH or Get-ChildItem before it silently does nothing under bash.

Windows notes

  • PowerShell 5.1 lacks &&, ||, ternary, ?., and ?? — this scanner exists because those keep leaking in from PS7 / bash habits.
  • Backtick line-continuations are joined into one logical line, so an -Encoding flag on the following line still counts. <# ... #> block comments and whole-line # comments are not scanned.
  • .bat files are out of scope — their traps are byte/parse-level, which is path-quirk-audit's domain.

Storage / exit codes

Read-only — writes nothing except inside a throwaway temp dir during --canary.

0 clean · 1 findings or canary failure · 2 usage error.

Verification (the done-check)

node shell-portability.js --canary

Self-tests both directions in a throwaway temp dir: the documented traps are CAUGHT (a bad .ps1 with && + a ternary + an unencoded Set-Content yields exactly 3 findings; ??, ?., Read-Host, bash-assign, and a bad .sh each caught) AND clean PS5.1-safe / POSIX code stays quiet (0 findings); the check mode catches a chained handed-over command and passes its chain-free form, in both dialects, and rejects an empty invocation; a trap inside a powershell -Command / pwsh -c payload is caught (in .ps1 and .sh), as is the exact -AsPlainText command that failed on 5.1 on 2026-09-28, while its 5.1-safe replacement is not; plus the # portability-ok suppression and an end-to-end directory walk. MUST print CANARY PASS 30/30 before you trust a result.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.