Shell Execution Context
Persistent Environment Model
Section titled “Persistent Environment Model”Think of Runbooks like a persistent terminal session. When you run scripts in Check or Command blocks, environment changes carry forward to subsequent blocks — just like typing commands in a terminal.
| What persists | Example |
|---|---|
| Environment variables | export AWS_PROFILE=prod stays set for later blocks |
| Working directory | cd /path/to/project changes where later scripts run |
| Unset variables | unset DEBUG removes the variable for later blocks |
This means you can structure your runbook like a workflow:
- Block 1: Set up environment (
export AWS_REGION=us-east-1) - Block 2: Run a command that uses
$AWS_REGION - Block 3: Clean up (
unset AWS_REGION)
Bash Scripts Only
Section titled “Bash Scripts Only”| Script Type | Can read env vars | Can set persistent env vars |
|---|---|---|
Bash (#!/bin/bash) | ✅ Yes | ✅ Yes |
Sh (#!/bin/sh) | ✅ Yes | ✅ Yes |
Python (#!/usr/bin/env python3) | ✅ Yes | ❌ No |
Ruby (#!/usr/bin/env ruby) | ✅ Yes | ❌ No |
Node.js (#!/usr/bin/env node) | ✅ Yes | ❌ No |
| Other interpreters | ✅ Yes | ❌ No |
Why? Environment persistence works by wrapping your script in a Bash wrapper that captures environment changes after execution. This wrapper is Bash-specific and can’t be applied to other interpreters. Additionally, environment changes in subprocesses (like a Python script) can’t propagate back to the parent process — this is a fundamental limitation of how Unix processes work.
Multiline Environment Variables
Section titled “Multiline Environment Variables”Environment variables can contain embedded newlines — RSA keys, JSON configs, multiline strings, etc. These values are correctly preserved across blocks:
#!/bin/bashexport SSH_KEY="-----BEGIN RSA PRIVATE KEY-----MIIEpAIBAAKCAQEA...-----END RSA PRIVATE KEY-----"
export JSON_CONFIG='{ "database": "postgres", "settings": { "timeout": 30 }}'Runbooks uses NUL-terminated output (env -0) when capturing environment variables, which correctly handles values containing newlines. This works on Linux, macOS, and Windows with Git Bash.
User Trap Support
Section titled “User Trap Support”Your scripts can optionally use trap commands for cleanup.
#!/bin/bashTEMP_DIR=$(mktemp -d)trap "rm -rf $TEMP_DIR" EXIT
# Your script logic...export RESULT="computed value"Runbooks intercepts EXIT traps to ensure both your cleanup code and environment capture (capturing the environment variables that were set in this script and making those values available to other scripts) run correctly. When your script exits:
- Your trap handler runs first (cleanup happens)
- Runbooks captures the final environment state
- The original exit code is preserved
This means you can write scripts with proper cleanup logic and still have environment changes persist to subsequent blocks.
Multiple Browser Tabs
Section titled “Multiple Browser Tabs”If you open the same runbook in multiple browser tabs, they all share the same environment. Changes made in one tab are visible in all others — like having multiple terminal windows connected to the same shell session.
Concurrent Script Execution
Section titled “Concurrent Script Execution”Why this happens: When a script starts, it captures the current environment as a snapshot. When it finishes, it replaces the session environment with whatever the script ended with. If two scripts run concurrently:
- Script A and Script B both start with environment
{X=1} - Script A sets
X=2 - Script B sets
Y=3 - Whichever finishes last overwrites the other’s changes
For example, if Script B finishes last, the session ends up with {X=1, Y=3} — losing Script A’s change to X.
Recommendation: If your scripts depend on environment changes from previous scripts, wait for each script to complete before running the next one. The environment model is designed for sequential, step-by-step execution, similar to typing commands in a terminal one at a time.
Implementation Notes
Section titled “Implementation Notes”The Runbooks server maintains a single session per runbook instance. Each script execution captures environment changes and working directory updates, then applies them to the session state. This happens automatically — you don’t need to do anything special in your scripts.
The session resets when you restart the Runbooks server. You can also manually reset the environment to its initial state using the session controls in the UI.
Built-in Environment Variables
Section titled “Built-in Environment Variables”Runbooks exposes the following environment variables to all scripts:
| Variable | Description |
|---|---|
RUNBOOKS_OUTPUT | Path to a directory where scripts can write files to be captured. Files written here appear in the generated files panel after successful execution. |
Capturing Output Files
Section titled “Capturing Output Files”To save files to the generated files directory, write them to $RUNBOOKS_OUTPUT:
#!/bin/bash# Generate a config and capture ittofu output -json > "$RUNBOOKS_OUTPUT/outputs.json"
# Create subdirectories as neededmkdir -p "$RUNBOOKS_OUTPUT/config"echo '{"env": "production"}' > "$RUNBOOKS_OUTPUT/config/settings.json"Files are only captured after successful execution (exit code 0 or 2). If your script fails, any files written to $RUNBOOKS_OUTPUT are discarded.
See Capturing Output Files for more details.
Non-Interactive Shell
Section titled “Non-Interactive Shell”Scripts run in a non-interactive shell, which affects what’s available:
| Feature | Available? | Notes |
|---|---|---|
| Environment variables | ✅ Yes | Inherited from Runbooks + changes from previous blocks |
Binaries in $PATH | ✅ Yes | git, aws, terraform, etc. |
| Shell aliases | ❌ No | ll, la, custom aliases |
| Shell functions | ❌ No | nvm, rvm, assume, etc. |
| RC files | ❌ No | .bashrc, .zshrc are NOT sourced |
Example: Aliases vs Binaries
Section titled “Example: Aliases vs Binaries”# ❌ Will NOT work - ll is typically a bash alias for "ls -l"<Check command="ll" ... />
# ✅ Will work - ls is an actual binary<Check command="ls -l" ... />Why This Matters
Section titled “Why This Matters”Many developer tools are implemented as shell functions rather than standalone binaries. These functions are defined in your shell’s RC files (.bashrc, .zshrc) and only exist in interactive shell sessions.
Common tools that are shell functions (not binaries):
- nvm — Node Version Manager
- rvm — Ruby Version Manager
- pyenv shell integration
- conda activate
- assume — Shell function from Granted
These tools need to be shell functions because they modify your current shell’s environment (e.g., changing $PATH), which can’t be done from a subprocess.
Workarounds
Section titled “Workarounds”For tools that are shell functions, check for the underlying installation instead:
#!/bin/bash# Instead of running "nvm --version" (won't work), check if nvm is installed:if [ -d "$HOME/.nvm" ] && [ -s "$HOME/.nvm/nvm.sh" ]; then echo "✅ nvm is installed" exit 0else echo "❌ nvm is not installed" exit 1fiIf you absolutely need shell functions, source the RC file in your script (use with caution):
#!/bin/bash# Source shell config to get functions (not recommended for portability)source ~/.bashrc 2>/dev/null || source ~/.zshrc 2>/dev/null
# Now nvm should be availablenvm --versionInterpreter Detection
Section titled “Interpreter Detection”Runbooks determines which interpreter to use for your script:
- Shebang line — If your script starts with
#!/bin/bash,#!/usr/bin/env python3, etc., that interpreter is used - Default — If no shebang is present,
bashis used
Common Shebangs
Section titled “Common Shebangs”| Shebang | Interpreter |
|---|---|
#!/bin/bash | Bash shell |
#!/bin/zsh | Zsh shell |
#!/usr/bin/env python3 | Python 3 |
#!/usr/bin/env node | Node.js |
Best Practice
Section titled “Best Practice”Always include a shebang in your scripts to ensure predictable execution:
#!/bin/bashset -e# Your script here...Demo Runbooks
Section titled “Demo Runbooks”The Runbooks repository includes demo runbooks that showcase these execution features:
Persistent Environment Demo
Section titled “Persistent Environment Demo”The demo-runbook-execution-model runbook demonstrates:
- Setting and reading environment variables across blocks
- Working directory persistence
- Multiline environment variables (RSA keys, JSON)
- Non-bash scripts reading (but not setting) persistent env vars
File Capture Demo
Section titled “File Capture Demo”The demo-runbook-capture-files-from-scripts runbook demonstrates:
- Using
$RUNBOOKS_OUTPUTto capture generated files - Combining environment persistence with file generation
- Creating OpenTofu configs from environment variables set in earlier blocks