Script engineering
Skill nledford/engineering-review-board/skills/script-engineering
Script and automation engineering guidance. Use when creating, changing, reviewing, or testing POSIX shell, Bash, zsh, Fish, PowerShell, Python, Ruby, Node, or other repository scripts; choosing a scripting language or interpreter; deciding whether automation belongs in a script or shell; or exposing script workflows through Just or package scripts. Do not use when only running an existing script or recipe, for ordinary application code with no automation surface, or for hosted CI/release-provider or container semantics beyond the commands scripts invoke.From its SKILL.md
npx -y skills add nledford/engineering-review-board --skill script-engineeringAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
15.5 KB, ~3.1k tokens by cl100k_base, as published. Nobody here has run it
Script Engineering
Use this skill for cross-language script selection and for the engineering rules shared by repository automation scripts. Derive the available runtimes, supported platforms, script layout, and validation commands from the target repository and execution environment instead of assuming a universal tool list.
Use the matching language engineering skill when implementation needs
language-specific depth. Use justfiles when changing
the Just command surface; this skill owns the script behind that surface.
Workflow
- Inspect repository instructions, script directories, shebangs, file extensions, manifests, version files, lockfiles, task runners, CI images, containers, tests, and documentation.
- Identify every execution target: developer hosts, Windows or Unix-like systems, containers, CI runners, remote hosts, or production automation.
- Decide whether the behavior should be a script. Prefer an existing command, task-runner recipe, application module, migration framework, or service when that is the clearer maintained boundary.
- Choose the least complex language that is already supported across the required targets. Do not add a runtime merely to make a small script more convenient to author.
- Define inputs, outputs, exit codes, side effects, working-directory rules, dependencies, idempotence expectations, preview behavior, and cleanup before implementing risky or reusable automation.
- Implement in small testable units. Keep command construction explicit, validate arguments, quote paths and values correctly for the chosen language, and avoid hidden ambient state.
- Run syntax/static checks and behavioral tests narrowly, then run the repository's broader script, task-runner, and CI-equivalent quality lanes.
- Report the runtime evidence, language choice, behavior covered, commands run, skipped target platforms, and residual risk.
Establish Runtime Availability
Treat availability as evidence about one target environment, not a fixed list:
- Repository evidence comes first: shebangs, existing scripts, version managers, package manifests, lockfiles, toolchain files, containers, CI configuration, setup docs, and task-runner recipes.
- Confirm the interpreter on each relevant target with a non-mutating lookup such
as
command -v <interpreter>,type <interpreter>, or PowerShellGet-Command <interpreter>, followed by the appropriate version command when version compatibility matters. - Distinguish POSIX
sh, Bash, and other shells. A working interactive shell does not prove that a script's shebang or requested shell exists elsewhere. - Distinguish PowerShell 7+ (
pwsh) from Windows PowerShell (powershell.exe) when features or platform support differ. - Treat an agent permission to request or execute a command as authorization, not proof that the interpreter is installed. A script never broadens the agent's edit, shell, network, external-directory, or destructive-action authority.
- If required target availability cannot be established, preserve the existing repository convention or stop and report the uncertainty rather than silently adding a new runtime assumption.
Decide Whether To Script
Do not create a durable script when:
- one short, readable, low-risk existing command or task-runner recipe is enough;
- the behavior is domain or application logic that callers should import and test through the normal application boundary;
- the repository already provides a maintained generator, migration tool, package command, or platform-native mechanism for the operation;
- the work needs a long-running process, durable state, recovery, rich concurrency, or an interactive interface better expressed as an application;
- a new interpreter or test framework would cost more than the automation saves; or
- the script would conceal destructive, credentialed, or remote operations, or work around command approval, sandbox, policy, or audit requirements.
One-off does not automatically mean unscripted. Data migrations, releases, and other high-risk operations often need a reviewed, repeatable implementation with preview, rollback, and evidence rather than an improvised terminal sequence.
Use the smallest durable boundary that remains understandable:
- keep one short, safe command inline;
- use a task-runner or package recipe as a discoverable thin entry point;
- move reusable or branching behavior into an independently tested script; and
- promote substantial domain behavior, concurrency, state, recovery, or public interfaces into an application module, library, or maintained CLI.
Do not keep growing a shell or package-script body after quoting, parsing, branching, cleanup, or state management becomes the main engineering work.
Choose A Language
Prefer the repository's established language when it satisfies the target platforms and keeps the workflow maintainable.
| Choice | Prefer when | Move to another language when |
|---|---|---|
POSIX sh | The script is a small portable sequence of commands with limited branching and no Bash-only features. | Arrays, complex data, substantial parsing, or non-POSIX features are required. |
| Bash | Unix-like targets guarantee Bash and shell-native orchestration, pipelines, traps, or Bash data structures materially simplify the task. | Portability excludes Bash, or quoting, parsing, branching, and state are becoming the main work. |
| zsh | The repository explicitly owns zsh configuration or every target guarantees the required zsh version and features. | The script is general repository automation, runs in CI/containers without zsh, or POSIX sh/Bash is sufficient. |
| Fish | The behavior is intentionally Fish-specific interactive configuration, functions, or completions for known Fish users. | The script is portable automation or must run under POSIX-compatible shells; Fish syntax is not POSIX shell syntax. |
| Python | The task handles structured data, files, APIs, reusable functions, robust CLI parsing, subprocess orchestration, or meaningful cross-platform behavior. | The repository does not support Python on every target, or a tiny shell command is clearer. |
| Ruby | The repository already supports Ruby and the automation benefits from Ruby code, locked gems, text/data handling, or a Ruby application/Rake boundary. | Ruby is absent from bootstrap or target hosts, or an existing supported language provides a clearer path. |
| PowerShell | Windows administration, registry/services, Microsoft modules, .NET objects, or an existing cross-platform PowerShell workflow is the natural boundary. | Required targets do not provide the needed PowerShell edition, or the repository already has a simpler supported runtime. |
| JavaScript or TypeScript | The repository already standardizes on Node, Bun, or Deno and the script benefits from its package/tooling ecosystem. | Adding that runtime would create a new dependency or the script is simpler in an existing shell/Python workflow. |
| Another existing runtime | Local evidence shows it is the repository's supported automation language and all targets provide it. | Selection is based only on author familiarity or introduces an otherwise unused toolchain. |
Load python-engineering for Python
implementation, packaging, and pytest/unittest workflow. Load
ruby-engineering for Ruby, Bundler, gems,
idioms, and Minitest/RSpec workflow. Load
powershell-engineering for idiomatic and
cross-platform PowerShell implementation, Pester, and PSScriptAnalyzer. Load
javascript-typescript-engineering
for JavaScript or TypeScript runtime, package, type, lint, and test workflow.
Do not select zsh or Fish merely because it is the author's interactive shell. Interactive convenience is not evidence that CI, containers, developer hosts, or production targets provide that shell.
Script Contract And Safety
- Keep scripts deterministic and non-interactive by default. Make prompts an explicit user-facing mode, never an accidental CI or agent dependency.
- Use documented arguments and environment variables. Validate required values and return nonzero exit codes with actionable stderr on failure.
- Keep machine-readable stdout stable when other tools consume it; send progress and diagnostics to stderr.
- Resolve working-directory and relative-path behavior deliberately. Do not assume the caller starts beside the script unless that is the documented contract.
- Use temporary directories or files with collision-safe creation and guaranteed
cleanup. Load
random-data-identifierswhen generated names, nonces, tokens, fixtures, or reproducible randomness are material. - Prefer idempotent behavior. For destructive, remote, production, or credentialed operations, provide a meaningful preview or dry-run, validate the exact target, and make the apply step explicit.
- Never print secrets. Avoid
eval, dynamically assembled shell command strings, and interpolation of untrusted values into a shell; prefer argument arrays or direct process APIs. - Pin or otherwise reproducibly provision non-standard interpreters, linters, runners, and helper binaries through the repository's existing dependency workflow.
Test Scripts
Start with observable behavior: arguments, environment inputs, stdout, stderr, exit status, created or changed files, cleanup, and external-command boundaries. Use temporary isolated fixtures and test failure paths as well as success.
| Script type | Syntax and static checks | Behavioral tests |
|---|---|---|
| POSIX shell | Run the target shell's no-execute syntax check where supported and ShellCheck with the intended dialect. | Run black-box tests under every shell/platform the repository claims to support. Prefer the existing runner; ShellSpec is an option when multi-shell behavior needs a framework. |
| Bash | Run bash -n and the repository's configured ShellCheck lane. | Prefer the existing Bash runner. bash_unit is suitable for function-oriented assertions, setup/teardown, status checks, and TAP output; Bats-core is suited to command-oriented Bash tests. |
| zsh or Fish | Run the selected shell's parser/no-execute check where available and any configured linter. | Test under the exact supported shell versions; do not use POSIX/Bash tests as proof of zsh or Fish behavior. |
| Python | Run the configured formatter, linter, and type checker as applicable. | Use the repository's pytest or unittest lane through its managed environment; test CLI behavior at process boundaries when invocation is part of the contract. |
| Ruby | Run ruby -c on affected entry points plus configured format/lint checks. | Use the repository's Minitest or RSpec lane through Bundler, with process-level tests when arguments, streams, or exit status are contractual. |
| PowerShell | Run the repository's parser or PSScriptAnalyzer lane when configured. | Use Pester for functions, modules, commands, side effects, and error behavior. Test both pwsh and Windows PowerShell only when both are supported targets. |
| JavaScript or TypeScript | Run the configured format, lint, type-check, and build lanes. | Use the repository's configured test runner and add process-level tests when the CLI contract matters. |
Static analysis is not a substitute for behavioral tests. Conversely, do not add
a test framework for a trivial wrapper when a syntax check plus one repository
smoke test provides proportionate confidence. Adding or downloading a runner,
linter, interpreter, binary, or installer invokes
dependency-supply-chain-review;
do not copy unpinned curl | shell installation examples into project workflows.
Use test-driven-development when new
behavior or a regression can be driven through Red-Green-Refactor. Use
systematic-debugging first for an active
unexplained script failure.
Use Scripts With Just
When a repository uses Just, expose supported workflows through small, documented recipes and keep substantial logic in independently testable scripts:
- Keep one short command inline when quoting, control flow, and reuse remain obvious. A shebang recipe can hold a modest self-contained operation.
- Move reusable logic, functions, substantial branching, robust argument parsing, or independently tested behavior to the repository's established script directory. Keep the recipe a thin parameterized wrapper.
- Resolve script paths from the Justfile location rather than relying on the caller's current directory.
- Pass deliberate arguments through the recipe instead of duplicating defaults, environment parsing, validation, or business rules in both layers.
- Provide narrow script-test recipes and include them in the repository's normal check or verification lane when local conventions support that shape. Derive actual recipe names from the repository rather than inventing universal names.
- Pair risky apply recipes with preview/status recipes and preserve the same target validation inside the script; a task-runner confirmation prompt is not the only safety control.
Load justfiles for recipe syntax, parameters, groups,
imports/modules, shell configuration, listing behavior, and Just validation.
Workflow Routing
- Load
ci-release-engineeringwhen the change affects hosted workflow triggers, jobs, permissions, artifacts, or automated release behavior; scripts own only the commands that workflow runs. - Load
container-engineeringwhen changing Dockerfile, OCI image, or Compose behavior; scripts own only their contained automation contract. - Load
security-reviewfor concrete scripts that handle credentials, secrets, auth, command execution, untrusted input, paths, privileged operations, or remote/production targets. Usesecurity-review-evidencewhen captured output, fixtures, or reports may contain sensitive values. - Consult current official documentation for version-specific behavior of an external interpreter, runner, linter, task runner, or module after inspecting the repository's pinned version and local usage.
Completion Evidence
Report:
- the repository and target-environment evidence used to establish runtimes;
- why a script was appropriate and why the selected language fit better than the credible local alternatives;
- changed script, tests, task-runner, dependency, and documentation files;
- syntax, static-analysis, behavioral, platform, and broader quality checks run; and
- skipped target environments, unverified interpreter assumptions, and residual operational or security risk.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.