Shef
Shef, a wordplay on “shell” and “chef”, is a powerful CLI tool for cooking up advanced shell recipes.
Inspired by CyberChef, Shef allows you to pipe commands together, add interactive
user prompts, loop using complex control structures, and build reusable workflows with advanced conditional logic.
Quick Start Example
The following example showcases a simple Shef recipe, giving you a quick glance at the syntax and functionality.
recipes: - name: "conditional" description: "A simple demo of conditional operations using direct prompt values" category: "demo" operations: - name: "Choose Fruit" id: "choose" command: 'echo "You selected: {{ .fruit }}"' prompts: - name: "fruit" type: "select" message: "Choose a fruit:" options: - "Apples" - "Oranges" - name: "Apple Operation" id: "apple" command: echo {{ style "bold" (color "red" "This is the apple operation!") }} condition: ".fruit == 'Apples'" - name: "Orange Operation" id: "orange" command: echo {{ style "bold" (color "yellow" "This is the orange operation!") }} condition: ".fruit == 'Oranges'"
Now that you’ve gotten acquainted with the basics, let’s explore Shef’s capabilities in depth!
Table of Contents
- Shef Features
- Bash Scripts and Shef: Complementary Tools
- Ugh. YAML? Really?
- Installation
- Quick Start
- Shef Command Reference
- Recipe Sources
- Recipe Structure
- Interactive Prompts
- Transformations
- Conditional Execution
- Branching Workflows
- Data Flow Between Operations
- Control Flow Structures
- Example Recipes
- Creating Recipes
- AI-Assisted Recipe Creation
- Troubleshooting
- Contributing to Shef
Shef Features
- Command Piping: Chain multiple commands together, passing output from one command to the next
- Transformations: Transform command output with powerful templating
- Interactive Prompts: Add user input, selections, confirmations, and more
- Conditional Logic: Use if/else branching based on command results
- Control Flow: Create dynamic workflows with loops and control structures
- Multiple Sources: Use local, user, or public recipes
- Organized Recipes: Categorize and share your recipes with others
Bash Scripts and Shef: Complementary Tools
Bash scripting is a powerful and valid approach for shell automation. Shef isn’t designed to replace bash scripts, but
rather provides a toolkit that compliments bash when you need specific features.
Shef implements some common tooling like built-in support for interactive prompts, conditional logic, and command
piping. This structured approach can simplify certain tasks that might require more verbose code in bash.
Consider Shef as another tool in your automation toolkit. Absolutely use bash scripts when they’re the right fit, and
reach for Shef when its features align with your specific needs.
Ugh. YAML? Really?
Sigh. Yep. Another config format. I considered several options, and YAML emerged as the most practical choice for
this particular use case. JSON lacks comments and multiline string support, which are essential when defining shell
commands and documenting workflows. XML would have been unnecessarily verbose. TOML, while nice, doesn’t handle nested
structures as elegantly for complex workflows.
Installation
Note
In the future, I would like to support these installation methods:
- Brew install
- APT install
- YUM/DNF install
- Arch User Repository (AUR)
- Standalone binary downloads
- Windows package managers (Chocolatey/Scoop)
Prerequisites
Before installing Shef, ensure you have Go installed and configured on your system:
-
Install Go: If you don’t have Go installed, download and install it from golang.org or
use your system’s package manager:# macOS (using Homebrew) brew install go # Ubuntu/Debian sudo apt update sudo apt install golang-go # Fedora sudo dnf install golang
-
Configure Go Environment: Ensure your Go environment is properly set up:
# Add these to your shell configuration (.bashrc, .zshrc, etc.) export GOPATH=$HOME/go export PATH=$PATH:$GOPATH/bin
-
Verify Installation: Confirm Go is correctly installed:
Quick Installation
The simplest way to install Shef is with Make:
# Clone the repository git clone git@github.com:eduardoagarcia/shef.git cd shef # Install (requires sudo for system-wide installation) make install # Or install to your home directory (no sudo required) make install-local
Manual Installation Options
Install with Go
Once you have Go installed, you can install Shef directly:
go install github.com/eduardoagarcia/shef@latest
This will install the shef
binary to your $GOPATH/bin
directory.
Build from Source
# Clone the repository git clone git@github.com:eduardoagarcia/shef.git # Build the application cd shef go build -o shef # Move to a directory in your PATH sudo mv shef /usr/local/bin/
Adding to PATH
If the installation directory is not in your PATH, you’ll need to add it:
# Add this to your .bashrc, .bash_profile, or .zshrc export PATH="$PATH:$GOPATH/bin" # For go install # OR export PATH="$PATH:$HOME/bin" # For make install-local
Then reload your shell configuration: source ~/.bashrc
(or ~/.zshrc
, ~/.bash_profile
depending on your shell)
Updating Shef
To update Shef to the latest version:
# Navigate to your local repository cd shef # Pull the latest changes git pull # Update system-wide installation (requires sudo) make update # Or update local installation (no sudo required) make update-local
Quick Start
Once Shef is installed, you are ready to begin using it.
# Sync all public recipes locally shef sync # Run the Hello World recipe shef demo hello-world # List available recipes shef ls # List all recipes within a category shef ls demo
Shef Command Reference
Basic Shef Command Structure
shef [category] [recipe-name]
Global Flags
Flag | Description |
---|---|
-h, --help |
Show help information |
-v, --version |
Show version information |
-d, --debug |
Enable debug output |
-c, --category |
Specify a category |
-L, --local |
Force local recipes first |
-U, --user |
Force user recipes first |
-P, --public |
Force public recipes first |
Utility Commands
Command | Description |
---|---|
sync |
Sync public recipes locally |
list ls l |
List available recipes |
Important
Make sure your Shef git repo is up to date before running shef sync
Recipe Sources
Shef looks for recipes in multiple locations:
- Local Recipes:
./.shef/*.yaml
in the current directory - User Recipes:
~/.shef/user/*.yaml
in your home directory - Public Recipes:
~/.shef/public/*.yaml
in your home directory
If you have recipes with the same name and category in different locations, you can prioritize a specific source:
shef -L git version # Prioritize local recipes shef -U git version # Prioritize user recipes shef -P git version # Prioritize public recipes
Recipe Structure
Recipes are defined in YAML files:
recipes: - name: "example" description: "An example recipe" category: "demo" operations: - name: "First Operation" id: "first_op" command: "echo 'Hello, World!'" - name: "Second Operation" command: "cat" transform: "{{ filter .input 'Hello' }}"
Key Recipe Components
- name: Unique identifier for the recipe
- description: Human-readable description
- category: Used for organization and filtering
- author: Optional author attribution
- operations: List of operations to execute in sequence
Operations
Operations are the building blocks of recipes:
- name: "Operation Name" # Operation name id: "unique_id" # Identifier for referencing output command: "echo 'Hello'" # Shell command to execute execution_mode: "standard" # [Optional] How the command runs (standard, interactive, or stream) silent: false # [Optional] Whether to suppress output to stdout condition: "var == true" # [Optional] Condition for execution on_success: "success_op" # [Optional] Operation to run on success on_failure: "failure_op" # [Optional] Operation to run on failure transform: "{{ .output | trim }}" # [Optional] Transform output prompts: # [Optional] Interactive prompts - name: "var_name" type: "input" message: "Enter value:" control_flow: # [Optional] Control flow structure (one of the below types) type: "foreach" # Type of control flow (foreach, for, while) operations: # [Optional] Sub-operations for when control flow structures are used - name: "Sub Operation" command: "echo 'Processing {{ .item }}'"
Control Flow Configuration
Control flow structures are configured as follows:
Foreach
control_flow: type: "foreach" # Iterate over a collection collection: "Item 1nItem 2" # Collection of items (newline separated) as: "item" # Variable name for current item
For
control_flow: type: "for" # Execute a fixed number of times count: 5 # Number of iterations variable: "i" # Variable name for iteration index (optional)
While
control_flow: type: "while" # Execute while condition is true condition: "{{ ne .status `ready` }}" # Condition to evaluate each iteration
Execution Modes
- standard: Default mode (used when no execution_mode is specified). Output is captured and can be used by
subsequent operations. - interactive: The command has direct access to the terminal’s stdin, stdout, and stderr. Useful for commands that
require direct terminal interaction, but output cannot be captured for use in subsequent operations. - stream: Similar to interactive mode but optimized for long-running processes that produce continuous output. The
command’s output streams to the terminal in real-time, but output cannot be captured for use in subsequent operations.
Interactive User Prompts
Shef supports the following types of user prompts:
Basic Input Types
# Text Input - name: "username" type: "input" message: "Enter your username:" default: "admin" help_text: "This will be used for authentication" # Selection - name: "environment" type: "select" message: "Select environment:" options: - "dev" - "staging" - "production" default: "dev" help_text: "Choose the deployment environment" # Confirmation (yes/no) - name: "confirm_deploy" type: "confirm" message: "Deploy to production?" default: "false" help_text: "This will start the deployment process" # Password (input is masked) - name: "password" type: "password" message: "Enter your password:" help_text: "Your input will be hidden"
Advanced Input Types
# Multi-select - name: "features" type: "multiselect" message: "Select features to enable:" options: - "logging" - "metrics" - "debugging" default: "logging,metrics" help_text: "Use space to toggle, enter to confirm" # Numeric Input - name: "count" type: "number" message: "Enter number of instances:" default: "3" min_value: 1 max_value: 10 help_text: "Value must be between 1 and 10" # File Path Input - name: "config_file" type: "path" message: "Select configuration file:" default: "./config.json" file_extensions: - "json" - "yaml" - "yml" required: true help_text: "File must exist and have the right extension" # Text Editor - name: "description" type: "editor" message: "Enter a detailed description:" default: "# Project DescriptionnnEnter details here..." editor_cmd: "vim" # Uses $EDITOR env var if not specified help_text: "This will open your text editor" # Autocomplete Selection - name: "service" type: "autocomplete" message: "Select a service:" options: - "authentication" - "database" - "storage" - "analytics" help_text: "Type to filter options"
Dynamic Options
You can generate selection options from a previous operation’s output:
- name: "List Files" id: "files_list" command: "find . -name '*.go'" - name: "Select File" command: "cat {{ .file }}" prompts: - name: "file" type: "select" message: "Select a file:" source_operation: "files_list" source_transform: "{{ .input | trim }}"
Transformations
Transformations let you modify a command’s output before it’s passed to the next operation or used in prompts.
Basic Syntax
transform: "{{ .output | function1 | function2 }}"
Available Transformation Functions
Function | Description | Example |
---|---|---|
trim |
Remove whitespace | {{ .output | trim }} |
split |
Split string by delimiter | {{ .output | split "," }} |
join |
Join array with delimiter | {{ .output | join "n" }} |
joinArray |
Join any array type with delimiter | {{ .output | joinArray "," }} |
filter |
Keep lines containing a pattern | {{ .output | filter "pattern" }} |
grep |
Alias for filter | {{ .output | grep "pattern" }} |
cut |
Extract field from each line | {{ .output | cut ":" 1 }} |
trimPrefix |
Remove prefix | {{ .output | trimPrefix "foo" }} |
trimSuffix |
Remove suffix | {{ .output | trimSuffix "bar" }} |
contains |
Check if string contains pattern | {{ if contains .output "pattern" }}yes{{ end }} |
replace |
Replace text | {{ .output | replace "old" "new" }} |
atoi |
Convert string to int | {{ .output | atoi }} |
add |
Add numbers | {{ .output | atoi | add 5 }} |
sub |
Subtract numbers | {{ .output | atoi | sub 3 }} |
div |
Divide numbers | {{ .output | atoi | div 2 }} |
mul |
Multiply numbers | {{ .output | atoi | mul 4 }} |
exec |
Execute command | {{ exec "date" }} |
color |
Add color to text | {{ color "green" "Success!" }} |
style |
Add styling to text | {{ style "bold" "Important!" }} |
resetFormat |
Reset all colors and styles | {{ resetFormat }} |
Terminal Colors and Styles
You can make your recipe outputs more readable by adding colors and styles. These are automatically disabled when using
the NO_COLOR
environment variable.
Available Colors
Color Type | Available Colors |
---|---|
Text Colors | black , red , green , yellow , blue , magenta , cyan , white |
Background Colors | bg-black , bg-red , bg-green , bg-yellow , bg-blue , bg-magenta , bg-cyan , bg-white |
Available Styles
Style | Description |
---|---|
bold |
Bold text |
dim |
Dimmed text |
italic |
Italic text |
underline |
Underlined text |
Using Colors and Styles
Colors and styles can be used in commands, transformations, and anywhere templates are rendered:
Basic Color Usage
command: echo "{{ color "green" "Success!" }}"
Basic Style Usage
command: echo "{{ style "bold" "Important!" }}"
Combine Color and Style
command: echo "{{ style "bold" (color "red" "Error!") }}"
Transformations
transform: | {{ if contains .output "error" }} {{ color "red" (style "bold" "✗ Operation failed") }} {{ else }} {{ color "green" (style "bold" "✓ Operation succeeded") }} {{ end }}
Accessing Variables
You can access all context variables in transformations:
transform: "{{ if eq .format `json` }}{{ .output }}{{ else }}{{ .output | cut ` ` 0 }}{{ end }}"
Variables available in templates:
.output
: The output to the current transformation (output from the command).input
: The input to the current command (input from previous operation).{prompt_name}
: Any variable from defined prompts.{operation_id}
: The output of a specific operation by ID.operationOutputs
: Map of all operation outputs by ID.operationResults
: Map of operation success/failure results by ID
Conditional Execution
Operations can be conditionally executed:
Basic Conditions
condition: .confirm == "true" # Run only if confirm prompt is true
Operation Result Conditions
condition: build_op.success # Run if build_op succeeded condition: test_op.failure # Run if test_op failed
Variable Comparison
condition: .environment == "production" # Equality check condition: .count != 0 # Inequality check
Numeric Comparison
condition: .count > 5 condition: .memory <= 512 condition: .errors >= 10 condition: .progress < 100
Complex Logic
condition: build_op.success && .confirm_deploy == "true" condition: test_op.failure || lint_op.failure condition: !.skip_validation
Branching Workflows
You can create branching workflows based on success or failure:
- name: "Build App" id: "build_op" command: "make build" on_success: "deploy_op" # Go to deploy_op on success on_failure: "fix_op" # Go to fix_op on failure - name: "Deploy" id: "deploy_op" command: "make deploy" - name: "Fix Issues" id: "fix_op" command: "make lint"
Data Flow Between Operations
Each operation’s output is automatically piped to the next operation’s input. You can also access any operation’s output
by its ID:
- name: "Get Hostname" id: "hostname_op" command: "hostname" - name: "Show Info" command: "echo 'Running on {{ .hostname_op }}'"
Control Flow Structures
Shef supports advanced control flow structures that let you create dynamic, iterative workflows.
Foreach Loops
You can iterate over a collection of items and perform a flow of operations on each item.
Key Foreach Components
- control_flow
- type: foreach
- collection: The list of items to iterate over (string with items separated by newlines)
- as: The variable name to use for the current item in each iteration
- operations: The sub-operations to perform for each item (all sub-operations have access to the
as
loop variable)
Mechanics of the Foreach Loop
- Parse the collection into separate items (splitting by newlines)
- For each item, set the variable specified in “as”
- Execute all operations in the foreach block for each item
- Clean up the loop variable when done
Common Uses
- Processing multiple files
- Handling lists of servers, containers, or resources
- Applying the same transformation to multiple inputs
- Building dynamic workflows based on discovered items
Tip
Within a foreach loop, you can use conditional operations, transformations, and all other Shef features.
Example Foreach Recipes
- name: "Process Each Item" control_flow: type: "foreach" collection: "🍎 Applesn🍌 Bananasn🍒 Cherriesn🍊 Oranges" as: "fruit" # Each item will be available as .fruit operations: - name: "Process Fruit" command: "echo 'Processing {{ .fruit }}'"
You can also generate the collection dynamically:
- name: "List Files" id: "files" command: "find . -type f -name '*.txt'" - name: "Process Each File" control_flow: type: "foreach" collection: "{{ .files }}" # Using output from previous operation as: "file" # Each item will be available as .file operations: - name: "Process File" command: "cat {{ .file }} | wc -l"
For Loops
You can execute a set of operations a fixed number of times.
Key For Loop Components
- control_flow
- type: for
- count: The number of iterations to execute
- variable: (Optional) The variable name to use for the current iteration index (defaults to “i”)
- operations: The sub-operations to perform for each iteration
Mechanics of the For Loop
- Parse and evaluate the count value to determine the number of iterations
- For each iteration, set the loop variable to the current index (starting from 0)
- Also set the
.iteration
variable to the 1-based iteration number - Execute all operations in the operations block for each iteration
- Clean up the loop variables when done
Common Uses
- Repeating an operation a fixed number of times
- Creating numbered resources or items
- Running tests multiple times
- Implementing retry logic with a maximum attempt limit
Tip
Within a for loop, both the specified variable (zero-based index) and .iteration
(one-based counter) are available.
Example For Loop Recipes
- name: "Run a For Loop" control_flow: type: "for" count: 5 variable: "i" operations: - name: "Print Iteration" command: "echo 'Running iteration {{ .iteration }} (zero-based index: {{ .i }})'"
You can also use a dynamic count:
- name: "Get Count" id: "count" command: "echo '3'" transform: "{{ trim .input }}" - name: "Dynamic For Loop" control_flow: type: "for" count: "{{ .count }}" variable: "step" operations: - name: "Execute Step" command: "echo 'Executing step {{ .step }} of {{ .count }}'"
While Loops
You can repeatedly execute operations as long as a condition remains true.
Key While Loop Components
- control_flow
- type: while
- condition: The condition to evaluate before each iteration
- operations: The sub-operations to perform for each iteration
Mechanics of the While Loop
- Evaluate the condition before each iteration
- If the condition is true, execute the operations and repeat
- If the condition is false, exit the loop
- An
.iteration
variable is automatically set to track the current iteration (starting from 1) - A safety limit prevents infinite loops (maximum 1000 iterations)
Common Uses
- Polling for a condition (e.g., waiting for a service to be ready)
- Processing data until a certain state is reached
- Implementing retry logic with conditional termination
- Continuously monitoring resources until a specific event occurs
Tip
Within a while loop, the .iteration
variable lets you track how many iterations have occurred.
Example While Loop Recipes
- name: "Initialize Status" id: "status" command: "echo 'running'" transform: "{{ trim .input }}" silent: true - name: "Wait For Completion" control_flow: type: "while" condition: "{{ contains .status `running` }}" operations: - name: "Check Status" command: "echo 'Checking status (iteration {{ .iteration }})...'" id: "status" transform: "{{ if eq .iteration 5 }}completed{{ else }}running{{ end }}"
Real-world polling example:
- name: "Poll Service Until Ready" control_flow: type: "while" condition: "{{ ne .status `ready` }}" operations: - name: "Check Service Status" command: "curl -s http://service/status" id: "status" transform: "{{ trim .input }}"
Example Recipes
Hello World
recipes: - name: "hello-world" description: "A simple hello world recipe" category: "demo" operations: - name: "Greet User" command: | echo "Hello, {{ .name }}!" echo "Current time: $(date)" echo "Welcome to Shef, the shell recipe tool." prompts: - name: "name" type: "input" message: "What is your name?" default: "World"
Conditional Operations
recipes: - name: "conditional" description: "A simple demo of conditional operations using direct prompt values" category: "demo" operations: - name: "Choose Fruit" id: "choose" command: 'echo "You selected: {{ .fruit }}"' prompts: - name: "fruit" type: "select" message: "Choose a fruit:" options: - "Apples" - "Oranges" - name: "Apple Operation" id: "apple" command: echo "This is the apple operation! 🍎" condition: ".fruit == 'Apples'" - name: "Orange Operation" id: "orange" command: echo "This is the orange operation! 🍊" condition: ".fruit == 'Oranges'"
Transformation Pipeline
recipes: - name: "transform" description: "A simple demo of data transformation and pipeline flow" category: "demo" operations: - name: "Generate a Simple List" id: "generate" command: | echo "apple banana cherry dragonfruit eggplant" - name: "Filter Items" id: "filter" command: "cat" transform: "{{ filter .input `a` }}" silent: true - name: "Display Results" id: "display" command: "echo 'Items containing `a`:n{{ .filter }}'"
Creating Recipes
To create your own recipes:
- Create your user directory:
mkdir -p ~/.shef/user
(if it does not already exist) - Create a new YAML file:
touch ~/.shef/user/my-recipes.yaml
- Build and develop your recipes following the instructions above
- Run
shef ls
to see your new recipes
AI-Assisted Recipe Creation
You can generate powerful Shef recipes quickly using AI tools like ChatGPT, Claude, or other large language models.
Using AI to Create Recipes
- Copy the prompt below
- Paste it into your AI assistant of choice
- Replace
[DESCRIBE YOUR WORKFLOW IN DETAIL]
with a detailed description of your recipe’s workflow - The AI will generate a complete Shef recipe based on your description
- Test and iterate until the recipe works as expected
Example Usage
Here’s an example of how to fill in your workflow description:
I need a Docker management workflow that helps me clean up unused containers and images to free up disk space.
The workflow should:
1. Show the current Docker disk usage
2. List all stopped containers and allow me to select which ones to remove
3. Confirm before removing the selected containers
4. List dangling images (unused) and allow me to select which ones to remove
5. Offer an option to perform a more aggressive cleanup (removing all unused images)
6. Show before/after disk usage comparison
7. Include error handling in case any operation fails
The recipe should be interactive and safe, requiring confirmation before any destructive operations.
Tips for Better Results
- Use the latest AI models with advanced reasoning capabilities
- Be specific about what commands should be executed at each step
- Mention if you need interactive prompts, conditions, or transformations
- For complex workflows, break down your requirements into clear, logical steps
- Include any specific error handling or conditional branches you need
- Request comments in the generated recipe to explain complex sections
- Ask the AI to analyze and iterate on its recipe solution, considering edge cases and improvements
- If the first recipe doesn’t fully meet your needs, refine your requirements and ask for adjustments
Remember, the AI-generated recipes can provide an excellent starting point that you can further customize to fit your
exact needs.
The Prompt
I need help creating a Shef recipe. Shef is a CLI tool that combines shell commands into reusable recipes defined in YAML.
[DESCRIBE YOUR WORKFLOW IN DETAIL]
A Shef recipe is defined in YAML with this structure:
recipes:
- name: "short-name"
description: "Human-readable description"
category: "category"
author: "optional author"
operations:
- name: "Operation Name"
id: "unique_id"
command: "shell command"
execution_mode: "standard|interactive|stream" # How the command runs
silent: true|false # Whether to suppress the command's output
condition: "optional condition"
on_success: "next_op_id"
on_failure: "fallback_op_id"
transform: "{{ .input | transformation }}"
prompts:
- name: "variable_name"
type: "input|select|confirm|password|multiselect|number|editor|path|autocomplete"
message: "Prompt message"
default: "Default value"
help_text: "Additional help information"
required: true|false # Whether input is required
options: ["option1", "option2"] # For select/multiselect/autocomplete types
source_operation: "operation_id" # For dynamic options
source_transform: "{{ .input | transform }}" # For processing source options
min_value: 0 # For number type
max_value: 100 # For number type
file_extensions: ["txt", "json"] # For path type
multiple_limit: 3 # For multiselect type
editor_cmd: "vim" # For editor type
control_flow:
type: "foreach|for|while" # Type of control flow
collection: "Item 1nItem 2nItem 3" # Items to iterate over (foreach loops)
as: "item" # Variable name for current item (foreach loops)
count: 5 # Number of iterations (for loops)
variable: "i" # Variable name for iteration index (for loops)
condition: "{{ lt .counter 5 }}" # Condition to check (while loops)
operations: # Operations to perform for each iteration
- name: "Sub Operation"
# command: "echo 'Processing {{ .item }}'" # foreach loop
# command: "echo 'Iteration {{ .i }} of 5'" # for loop
# command: "echo 'While iteration {{ .iteration }}'" # while loop
RECIPE MECHANICS:
1. Operations execute in sequence unless redirected by on_success/on_failure
2. Each operation's output becomes input to the next operation
3. Variables from prompts are accessible as {{ .variable_name }}
4. Operation outputs are accessible as {{ .operation_id }}
5. You can combine variables and operation outputs in command templates
6. Control flow structures like foreach allow iterating over collections
CONTROL FLOW STRUCTURES:
- foreach: Iterate over a collection of items
- collection: Newline-separated list of items (can be fixed or from operation output)
- as: Variable name to assign each item during iteration
- operations: Operations to execute for each item (with access to the iteration variable)
- for: Execute operations a fixed number of times
- count: Number of iterations to perform (can be fixed or from operation output)
- variable: Variable name for the current zero-based index (optional, defaults to "i")
- operations: Operations to execute for each iteration (with access to the index variable and .iteration)
- while: Execute operations as long as a condition is true
- condition: Expression to evaluate before each iteration
- operations: Operations to execute while the condition is true (with access to .iteration)
INTERACTIVE PROMPTS:
- input: Free text input (default: string)
- select: Choose from options (static or dynamic from previous operation)
- confirm: Yes/no boolean question
- password: Masked text input
- multiselect: Choose multiple options
- number: Numeric input with range validation
- editor: Multi-line text input in an editor
- path: File path with validation
- autocomplete: Selection with filtering
TRANSFORMATION EXAMPLES:
- Trim whitespace: {{ .input | trim }}
- Split by delimiter: {{ .input | split "," }}
- Join array: {{ .input | join "n" }}
- Filter lines: {{ .input | filter "pattern" }} or {{ .input | grep "pattern" }}
- Extract field: {{ .input | cut ":" 1 }}
- Remove prefix/suffix: {{ .input | trimPrefix "foo" }} {{ .input | trimSuffix "bar" }}
- Check content: {{ if contains .input "pattern" }}yes{{ end }}
- Replace text: {{ .input | replace "old" "new" }}
- Math operations: {{ .input | atoi | add 5 | mul 2 | div 3 | sub 1 }}
- Execute command: {{ exec "date" }}
CONDITIONAL LOGIC:
- Variable equality: variable == "value" or variable != "value"
- Operation success/failure: operation_id.success or operation_id.failure
- Boolean operators: condition1 && condition2, condition1 || condition2, !condition
- Numeric comparison: value > 5, count <= 10
- Complex example: (check_files.success && has_tests == true) || skip_tests == true
ADVANCED FEATURES:
- Dynamic selection options from previous commands
- Conditional branching based on operation results
- Multi-step workflows with error handling
- Custom error messages and recovery steps
- Transforming outputs between operations
- Execution modes (standard or interactive)
- Silent operations that suppress output
EXAMPLE RECIPE PATTERNS:
1. Get input → Process → Show result
2. List options → Select one → Take action
3. Check condition → Branch based on result → Handle each case
4. Execute command → Transform output → Use in next command
5. Try operation → Handle success/failure differently
Please create a complete Shef recipe that accomplishes my goal, with proper indentation and comments explaining complex parts.
Troubleshooting
Common Issues
Recipe not found
- Check if you're using the correct name and category
- Use
shef ls
to see available recipes - Check your recipe file syntax
Command fails with unexpected output
- Remember all commands run through a shell, so shell syntax applies
- Escape special characters in command strings
- Use the
transform
field to format output
Prompt validation errors
- Ensure minimum/maximum values are within range
- Check that file paths exist and have correct extensions
- Verify select options contain the default value
Contributing to Shef
Thank you for taking an interest in contributing to Shef!
Contributing Code
Development Setup
-
Fork the Repository
# Fork via GitHub UI, then clone your fork git clone git@github.com:yourusername/shef.git cd shef
-
Set Up Development Environment
# Install development dependencies go mod download # Build the development version go build -o shef
-
Create a New Branch
git checkout -b my-awesome-feature
Development Guidelines
- Code Style: Follow standard Go conventions and the existing style in the codebase
- Documentation: Update documentation for any new features or changes
- Commit Messages: Write clear, descriptive commit messages explaining your changes
- Tests: Update tests accordingly
Submitting Your Changes
-
Push to Your Fork
git push origin my-awesome-feature
-
Create a Pull Request: Visit your fork on GitHub and create a pull request against the main repository
-
PR Description: Include a clear description of what your changes do and why they should be included
-
Code Review: Respond to any feedback during the review process
Contributing Recipes
Sharing your recipes helps grow the Shef ecosystem and benefits the entire community.
Creating Public Recipes
-
Develop and Test Your Recipe Locally
# Create your recipe in the user directory first mkdir -p ~/.shef/user vim ~/.shef/user/my-recipe.yaml # Test thoroughly shef -U my-category my-recipe-name
-
Recipe Quality Guidelines
- Include clear descriptions for the recipe and each operation
- Add helpful prompts with descriptive messages and defaults
- Handle errors gracefully
- Follow YAML best practices
- Comment complex transformations or conditionals
-
Submitting Your Recipe
Option 1: Via Pull Request
- Fork the Shef repository
- Add your recipe to the
recipes/public/
directory - Create a pull request with your recipe
Option 2: Via Issue
- Create a new issue on the Shef repository
- Attach your recipe file or paste its contents
- Describe what your recipe does and why it's useful
Recipe Documentation
When submitting a recipe, include a section in your PR or issue that explains:
- Purpose: What problem does your recipe solve?
- Usage: How to use the recipe, including example commands
- Requirements: Any special requirements or dependencies
- Examples: Sample outputs or use cases
Community Guidelines
- Be respectful of others' contributions
- Help review pull requests and test others' recipes
- Report bugs and suggest improvements
- Share your Shef success stories and use cases
Getting Help
If you need help with your contribution, you can:
- Open an issue on GitHub
- Ask questions in the discussions section
- Contact us directly