shuck

Managed Runtime

shuck run executes shell scripts with a resolved interpreter version instead of whatever shell happens to be on your machine. That gives you a lightweight way to pin Bash, Zsh, Dash, or mksh versions for local scripts, CI jobs, and one-off commands.

Managed interpreters are downloaded on demand, cached globally, and reused across projects. The related shuck install and shuck shell commands use the same resolver and cache.

Basic usage

# Run a script with the shell and version Shuck resolves for it
shuck run deploy.sh
 
# Pin both the shell and version from the CLI
shuck run --shell bash --shell-version 5.2 deploy.sh
 
# Run an inline command string
shuck run --shell zsh --shell-version 5.9 -c 'print $ZSH_VERSION'
 
# Read the script from stdin
printf 'echo hello\n' | shuck run --shell dash -
 
# Pass arguments through to the script
shuck run deploy.sh -- --env staging --force

Supported managed shells today are bash, zsh, dash, and mksh.

How resolution works

Shuck resolves the shell name and version separately.

For the shell name, precedence is:

  1. --shell
  2. Inline script metadata
  3. [run].shell in shuck.toml or .shuck.toml
  4. Shebang or file-extension inference
  5. Default bash

For the version constraint, precedence is:

  1. --shell-version
  2. Inline script metadata
  3. [run.shells].<shell>
  4. [run].shell-version
  5. latest

[run.shells] is evaluated after the shell has been resolved, so you can keep different default pins for different interpreters in the same project.

shuck run has one special fallback: if you do not provide a script path, metadata, config, shell, or version, it uses the system bash on your PATH. As soon as Shuck resolves something more specific, it uses the managed-runtime path instead.

Inline script metadata

Scripts can declare their runtime requirements in a leading metadata block:

# /// shuck
# shell = "bash"
# version = ">=5.1,<6"
# [metadata]
# description = "Deploy the staging stack"
# ///
 
set -euo pipefail

The metadata block must stay in the leading comment header, and only one # /// shuck block is allowed per script.

Shuck currently understands:

  • shell
  • version
  • an optional [metadata] table for informational fields such as description

Unknown keys are rejected so typos fail fast.

Project defaults

Use the [run] section in shuck.toml or .shuck.toml to set project-wide defaults:

[run]
shell = "bash"
shell-version = "5.2"
 
[run.shells]
bash = "5.2"
zsh = "5.9"
dash = "0.5.12"
mksh = "59c"

This is especially useful when a repository mixes shell dialects or needs to hold Bash on a newer version than the one that ships with macOS.

Runtime commands follow the same config discovery and override model as shuck check, including --config and --isolated. See Configuration for the full config search rules and Settings Reference for the generated key reference.

System vs managed interpreters

Use --system when you explicitly want the interpreter already installed on your machine:

shuck run --system --shell bash --shell-version '>=5.1' deploy.sh

Shuck still validates the system interpreter version against your requested constraint. If the version does not match, the command fails and tells you to install a managed version instead.

Without --system, Shuck downloads the matching interpreter into ~/.shuck/shells/ and reuses that cached copy for later runs.

shuck install preloads interpreters without running a script:

shuck install bash 5.2
shuck install --list
shuck install --list bash

shuck shell starts an interactive managed shell session:

shuck shell --shell bash --shell-version 5.2

Unlike shuck run, shuck shell defaults to a managed Bash session when nothing more specific is configured.

Runtime environment

Before executing a script, Shuck exports a few environment variables describing the resolved interpreter:

  • SHUCK_SHELL
  • SHUCK_SHELL_VERSION
  • SHUCK_SHELL_PATH

For managed interpreters, it also sets SHELL to the resolved binary path.

Current scope

Managed runtime support currently targets Unix-like environments with published managed shell artifacts. shuck run does not support Windows yet.