Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    bradreaves

    shell-script-installer

    bradreaves/shell-script-installer
    Coding
    1 installs

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    Use this skill when the user wants to create, write, or install shell scripts.

    SKILL.md

    Shell Script Installer Skill

    This skill helps you create and install shell scripts to the user's PATH.

    When to Use This Skill

    Activate this skill when the user:

    • Asks to create a shell script (fish, bash, zsh, sh)
    • Wants to install a script to their PATH
    • Needs a command-line utility or tool
    • Mentions writing executable scripts

    Shell Preference

    Default to Fish shell for all new scripts unless:

    • User explicitly requests bash/zsh/sh
    • Building on or extending an existing bash script
    • The script requires bash-specific features not available in Fish
    • There's a compelling compatibility reason (e.g., sharing with non-Fish users)

    Installation Directory

    Install all scripts to: ~/bin/scripts

    IMPORTANT: ~/bin/scripts is a git repository. All script creation and editing must use proper git workflow.

    Workflow

    Follow these steps in order:

    1. Understand Requirements

    • Ask what the script should do
    • Determine the script name (without extension)
    • Determine shell interpreter (default: fish, fallback to bash only if necessary)

    2. Set Up Git Workspace

    • Navigate to the scripts repository: cd ~/bin/scripts
    • Check current git status to ensure clean state
    • Create a new branch for this script: git checkout -b add-<script-name>
    • The branch name should be descriptive (e.g., add-backup-tool, add-git-helper)

    3. Write the Script

    • Create the script in the repository: ~/bin/scripts/<script-name>
    • Include proper shebang line:
      • For Fish: #!/usr/bin/env fish
      • For Bash: #!/usr/bin/env bash
    • Add helpful comments
    • Include error handling where appropriate
    • Follow shell scripting best practices for the chosen shell

    4. Review with User

    • Show the complete script to the user
    • Explain what it does
    • Ask if they'd like to make any changes

    5. Iterate (if needed)

    • If user requests changes, edit the script in place
    • Each iteration happens on the same git branch
    • Repeat review until user is satisfied

    6. Test (Interactive)

    • Ask the user if they want to test the script before committing
    • Make the script executable: chmod +x ~/bin/scripts/<script-name>
    • Offer a test command or let them test manually
    • Review test results with the user
    • If tests fail, go back to iteration (step 5)

    7. Commit and Merge

    • Ask for confirmation: "Ready to commit and install <script-name>?"
    • If confirmed:
      • Stage the script: git add <script-name>
      • Commit with detailed structured message (see "Git Commit Message Standards" section below)
        • Include Features section listing all capabilities
        • Include Technical details section with implementation notes
        • Include Co-Authored-By attribution for AI assistance
      • Switch back to main branch: git checkout main
      • Merge the feature branch: git merge add-<script-name>
      • REQUIRED: Delete the feature branch: git branch -d add-<script-name>
        • CRITICAL: Always delete merged feature branches to keep the repository clean
        • Never leave merged branches lingering in the repository
        • This is mandatory, not optional

    8. Verify PATH

    • Check if ~/bin/scripts is in the user's PATH
    • If not, inform the user and provide instructions to add it:
      # For Fish: add to ~/.config/fish/config.fish
      fish_add_path $HOME/bin/scripts
      
      # For bash: add to ~/.bashrc or ~/.bash_profile
      # For zsh: add to ~/.zshrc
      export PATH="$HOME/bin/scripts:$PATH"
      

    9. Final Verification

    • Test that the script is accessible: which <script-name>
    • Provide usage instructions
    • Suggest restarting the shell or sourcing the config if PATH was just updated

    Structured Logging Standards

    CRITICAL: All scripts must implement structured logging using the logger command.

    Logging Format

    • Use logger command with structured key=value format
    • Tag format: scriptname[PID] (use $$ for PID in bash, $fish_pid in fish)
    • IMPORTANT: In Fish, always use $fish_pid to get the process ID, NOT $$ or %self
    • Preserve user-facing output (echo/printf) while adding diagnostic logging to syslog

    Log Level Mapping

    Map script events to appropriate log levels:

    • user.info: Process status, file operations, success events

      • Example: "Processing file", "Operation completed successfully"
    • user.warning: Unsupported formats, non-critical issues, recoverable errors

      • Example: "Unsupported file format", "Feature not available"
    • user.error: Missing dependencies, failures, exit conditions

      • Example: "Required tool not found", "Failed to write file"
    • user.debug: File creation, skipped files, detailed operations

      • Example: "Created directory", "Skipping cached file"

    Logging Examples

    Fish:

    logger -t (basename (status filename))"[$fish_pid]" -p user.info "action=start status=processing"
    logger -t (basename (status filename))"[$fish_pid]" -p user.error "action=fail error=\"missing dependency\""
    

    Bash:

    logger -t "$(basename "$0")[$$]" -p user.info "action=start status=processing"
    logger -t "$(basename "$0")[$$]" -p user.error "action=fail error=\"missing dependency\""
    

    Input/Output Standards (REQUIRED FOR DATA-PROCESSING SCRIPTS)

    CRITICAL: Scripts that process data (read input, transform, write output) MUST follow these I/O standards.

    Input Handling

    Default to stdin when no file argument is provided:

    set input_file "-"
    if test (count $argv) -gt 0
        set input_file $argv[1]
    end
    
    # Validate file exists (if not stdin)
    if test "$input_file" != "-" -a ! -f "$input_file"
        echo "Error: Input file not found: $input_file" >&2
        log_error "action=read_input status=not_found file=\"$input_file\""
        exit 2
    end
    

    Output Handling

    Default to stdout, but provide -o/--output flag for file output:

    set output_file "-"
    set append_mode 0
    
    argparse 'o/output=' 'a/append' -- $argv
    if set -q _flag_output
        set output_file $_flag_output
    end
    if set -q _flag_append
        set append_mode 1
    end
    
    # Validate: append requires output file
    if test $append_mode -eq 1 -a "$output_file" = "-"
        echo "Error: --append requires --output to specify a file" >&2
        exit 2
    end
    

    Stream Separation (CRITICAL)

    stdout = data, stderr = messages

    # WRONG - mixes data and messages
    echo "Processing 100 items..."
    echo "$result_data"
    
    # CORRECT - separates streams
    echo "Processing 100 items..." >&2  # Progress to stderr
    echo "$result_data"                  # Data to stdout
    

    Why: Pipes capture stdout only. Messages on stderr appear to user but don't pollute the data stream.

    Structured Data Output

    For structured data, prefer TSV (tab-separated values):

    # TSV format (no header, easy to pipe)
    echo -e "$url\t$title\t$format\t$notes"
    

    Benefits:

    • Easy to process with cut, awk, sort
    • No quoting issues like CSV
    • Append-friendly (no header row to skip)
    • Pipe-friendly for tool chaining

    Progress Output Pattern (REQUIRED FOR MULTI-ITEM PROCESSING)

    For scripts that iterate over multiple items or perform long-running operations:

    # Auto-detect interactive vs batch mode
    set progress_mode 0
    if isatty stderr
        set progress_mode 1  # Interactive - show progress by default
    end
    
    # Parse flags (in argparse)
    argparse 'progress' 'no-progress' -- $argv
    
    # Explicit flags override auto-detection
    if set -q _flag_progress
        set progress_mode 1
    end
    if set -q _flag_no_progress
        set progress_mode 0
    end
    
    # In processing loop:
    set current 0
    set total (count $items)
    
    for item in $items
        set current (math $current + 1)
    
        if test $progress_mode -eq 1
            # Non-scrolling in-place update (\r returns to start of line)
            printf "\r[%d/%d] %s" $current $total "$item" >&2
        end
    
        # ... do work ...
    end
    
    # Final newline to complete the progress line
    if test $progress_mode -eq 1
        printf "\n" >&2
    end
    
    # Summary stats to stderr (always show, even in no-progress mode)
    echo "Results: $valid valid, $invalid invalid" >&2
    

    Key Points:

    • Use printf "\r..." for non-scrolling in-place updates
    • Progress goes to stderr, not stdout
    • Auto-detect TTY, but allow explicit override
    • Always show final summary statistics

    Pipe Support Standards (REQUIRED FOR DATA-PROCESSING SCRIPTS)

    Design Principles

    1. Composable: Output should be valid input for similar tools
    2. Silent on success: Only output data, not progress (unless --progress)
    3. No prompts: Never ask for interactive input in pipe mode
    4. Handle broken pipes: Gracefully handle downstream commands exiting early

    Making Scripts Pipe-Friendly

    # Example: Enable piping between related tools
    cat urls.txt | extract-urls | validate-urls | download-videos
    
    # Each script in the chain:
    # - Reads from stdin OR file
    # - Writes data to stdout
    # - Writes progress/errors to stderr
    # - Uses consistent format (one-per-line or TSV)
    

    Example Usage Patterns

    Add these to your usage() function:

    echo "Examples:"
    echo "  $SCRIPT_NAME input.txt -o output.txt"
    echo "  cat input.txt | $SCRIPT_NAME"
    echo "  $SCRIPT_NAME < input.txt > output.txt"
    echo "  $SCRIPT_NAME input.txt | other-tool"
    

    Best Practices

    CLI Standards (REQUIRED)

    Core Flags (All Scripts)

    • Always include --help / -h argument with usage information
    • Always include --version / -v argument showing script version
    • Always include --test argument that runs unit and regression tests of the code
    • Always include --fish-completions argument that installs fish shell tab completions to ~/.config/fish/completions/<script-name>.fish
      • Completions must include all flags (--help, --version, --test, --fish-completions, and any script-specific flags)
      • Completions should include context-aware argument completion where applicable
      • Must error if completion file already exists (prevents accidental overwrite)

    Data-Processing Script Flags (REQUIRED for scripts that process input→output)

    Scripts that process input data and produce output MUST also include:

    • -o / --output FILE - Write output to FILE instead of stdout (default: stdout)
    • -a / --append - Append to output file instead of overwriting (requires -o)

    Multi-Item Processing Flags (REQUIRED for scripts that iterate over items)

    Scripts that process multiple items or perform long-running operations MUST include:

    • --progress - Force in-place progress updates (even in batch mode)
    • --no-progress - Suppress progress updates (even in interactive mode)
    • Default behavior: Auto-detect based on isatty stderr (interactive = progress on, batch = progress off)

    General Guidelines

    • Document all command-line options clearly
    • Follow standard Unix conventions for flags and arguments

    Installation Documentation (REQUIRED)

    • Include installation instructions in a comment at the top of every script
    • Scripts should be self-documenting about where they belong in the filesystem
    • Examples:
      • Standalone command-line tool: # Installation: Copy to ~/bin/scripts
      • Fish function that needs to be sourced: # Installation: Copy to ~/.config/fish/functions
      • Shell configuration addon: # Installation: Source from ~/.config/fish/config.fish or ~/.bashrc
    • Make it clear if there are any post-installation setup steps required

    For Fish Scripts (Preferred)

    CRITICAL: Fish shell has specific behaviors that differ from bash/zsh. See the comprehensive guide at ~/fish-shell-rules.md for detailed rules, examples, and bug history from this project.

    Most Critical Fish-Specific Rules

    1. Variable Scoping: Use set -g (not set -l) for variables accessed across functions

      # WRONG: set -l urls "..."  # Will be empty in called functions
      # CORRECT: set -g urls "..."  # Visible everywhere
      
    2. Directory Changes: Fish (cd dir && cmd) does NOT create subshell - always save/restore $PWD

      # WRONG: (cd "$temp" && process)  # Changes parent directory!
      # CORRECT: set orig $PWD; cd "$temp"; process; cd "$orig"
      
    3. Multi-line Output: Use | string collect to preserve newlines in command substitution

      # WRONG: set output (command)  # Collapses newlines to spaces
      # CORRECT: set output (command | string collect)
      
    4. stdin Detection: Always check for empty args before reading stdin

      # WRONG: if not isatty stdin  # False positive with redirects
      # CORRECT: if test (count $argv) -eq 0; and not isatty stdin
      
    5. Array Iteration: Use direct iteration (never echo/split)

      # WRONG: for x in (echo "$array" | string split \n)
      # CORRECT: for x in $array
      
    6. String Operations: Use Fish's string built-in instead of grep/sed/awk

      # WRONG: echo "$text" | grep "pattern"
      # CORRECT: string match "*pattern*" $text
      

    See ~/fish-shell-rules.md for complete rules and the commit history showing why these rules exist.

    General Fish Best Practices

    • Use #!/usr/bin/env fish for portability
    • Include usage/help information with --help and --version flags
    • Use Fish's built-in error handling and status checks
    • Leverage Fish's modern syntax and features (argparse, functions)
    • Make scripts user-friendly with clear error messages
    • Avoid hardcoded paths when possible
    • Implement structured logging as described above

    For Bash Scripts (When Necessary)

    • Use #!/usr/bin/env bash for portability
    • Include usage/help information with --help and --version flags
    • Add error handling with set -e or appropriate error checks
    • Follow bash best practices
    • Implement structured logging as described above

    Path Handling

    • Be careful with cd commands: When scripts change directories, subsequent operations with relative paths may break
    • Use absolute paths when possible, especially after directory changes
    • Store original working directory if you need to return: set origin_dir (pwd) (fish) or origin_dir=$(pwd) (bash)
    • Test path resolution thoroughly, especially in refactored code

    Tool Design Philosophy

    • Make tools general-purpose rather than solution-specific when possible
    • Design for reusability and composability
    • Separate concerns: one tool should do one thing well
    • Consider how the tool might be used in different contexts

    Configuration Management

    • Separate configuration from code whenever practical
    • Extract prompts, templates, and settings to separate files
    • Use environment variables or config files for user-customizable values
    • Document configuration options clearly

    Testing Requirements

    • Test thoroughly after major refactoring, especially:
      • Path resolution and file access
      • Directory changes and relative paths
      • Error handling and edge cases
      • All command-line flags and options
    • Verify structured logging outputs correct levels and formats
    • Test with both valid and invalid inputs

    Example Script Templates

    Fish Script Template (Preferred)

    #!/usr/bin/env fish
    
    # Script: example-script
    # Version: 1.0.0
    # Description: What this script does
    # Installation: Copy to ~/bin/scripts
    
    set VERSION "1.0.0"
    set SCRIPT_NAME (basename (status filename))
    
    function log_info
        logger -t "$SCRIPT_NAME[$fish_pid]" -p user.info $argv
    end
    
    function log_error
        logger -t "$SCRIPT_NAME[$fish_pid]" -p user.error $argv
    end
    
    function log_debug
        logger -t "$SCRIPT_NAME[$fish_pid]" -p user.debug $argv
    end
    
    function show_version
        echo "$SCRIPT_NAME version $VERSION"
        exit 0
    end
    
    function run_tests
        log_info "action=test status=starting"
    
        # Add unit and regression tests here
        echo "Running unit tests..."
    
        # Example test placeholder
        # Replace with actual test logic
        echo "All tests passed!"
    
        log_info "action=test status=complete"
        exit 0
    end
    
    function install_fish_completions
        set -l completions_file ~/.config/fish/completions/$SCRIPT_NAME.fish
    
        # Check if file already exists
        if test -f "$completions_file"
            echo "Error: Completions file already exists: $completions_file" >&2
            echo "Remove it first if you want to regenerate completions." >&2
            exit 1
        end
    
        # Ensure directory exists
        mkdir -p ~/.config/fish/completions
    
        # Generate and write completions
        echo "# Fish completions for $SCRIPT_NAME
    # Generated by $SCRIPT_NAME --fish-completions
    
    # Complete flags
    complete -c $SCRIPT_NAME -s h -l help -d 'Show help message'
    complete -c $SCRIPT_NAME -s v -l version -d 'Show version information'
    complete -c $SCRIPT_NAME -l test -d 'Run unit and regression tests'
    complete -c $SCRIPT_NAME -l fish-completions -d 'Install fish shell completions'
    
    # Add script-specific completions here
    " > "$completions_file"
    
        and begin
            echo "Fish completions installed to: $completions_file"
            echo ""
            echo "Completions will be available in new fish shell sessions."
            echo "To use them immediately in this session, run:"
            echo "  source $completions_file"
        end
        or begin
            echo "Error: Failed to write completions file" >&2
            exit 1
        end
    
        exit 0
    end
    
    function usage
        echo "Usage: $SCRIPT_NAME [options]"
        echo ""
        echo "Description: What this script does"
        echo ""
        echo "Options:"
        echo "  -h, --help            Show this help message"
        echo "  -v, --version         Show version information"
        echo "  --test                Run unit and regression tests"
        echo "  --fish-completions    Install fish shell completions"
        exit 0
    end
    
    function main
        log_info "action=start status=processing"
    
        # Your script logic here
        echo "Hello from example Fish script!"
    
        log_info "action=complete status=success"
    end
    
    # Parse arguments
    argparse 'h/help' 'v/version' 'test' 'fish-completions' -- $argv
    or begin
        usage
    end
    
    if set -q _flag_help
        usage
    end
    
    if set -q _flag_version
        show_version
    end
    
    if set -q _flag_test
        run_tests
    end
    
    if set -q _flag_fish_completions
        install_fish_completions
    end
    
    log_debug "action=init args=\"$argv\""
    main
    

    Bash Script Template (Fallback)

    #!/usr/bin/env bash
    set -e
    
    # Script: example-script
    # Version: 1.0.0
    # Description: What this script does
    # Installation: Copy to ~/bin/scripts
    
    VERSION="1.0.0"
    SCRIPT_NAME="$(basename "$0")"
    
    log_info() {
        logger -t "${SCRIPT_NAME}[$$]" -p user.info "$@"
    }
    
    log_error() {
        logger -t "${SCRIPT_NAME}[$$]" -p user.error "$@"
    }
    
    log_debug() {
        logger -t "${SCRIPT_NAME}[$$]" -p user.debug "$@"
    }
    
    show_version() {
        echo "$SCRIPT_NAME version $VERSION"
        exit 0
    }
    
    run_tests() {
        log_info "action=test status=starting"
    
        # Add unit and regression tests here
        echo "Running unit tests..."
    
        # Example test placeholder
        # Replace with actual test logic
        echo "All tests passed!"
    
        log_info "action=test status=complete"
        exit 0
    }
    
    install_fish_completions() {
        local completions_file=~/.config/fish/completions/$SCRIPT_NAME.fish
    
        # Check if file already exists
        if [[ -f "$completions_file" ]]; then
            echo "Error: Completions file already exists: $completions_file" >&2
            echo "Remove it first if you want to regenerate completions." >&2
            exit 1
        fi
    
        # Ensure directory exists
        mkdir -p ~/.config/fish/completions
    
        # Generate and write completions
        cat > "$completions_file" << 'EOF'
    # Fish completions for $SCRIPT_NAME
    # Generated by $SCRIPT_NAME --fish-completions
    
    # Complete flags
    complete -c $SCRIPT_NAME -s h -l help -d 'Show help message'
    complete -c $SCRIPT_NAME -s v -l version -d 'Show version information'
    complete -c $SCRIPT_NAME -l test -d 'Run unit and regression tests'
    complete -c $SCRIPT_NAME -l fish-completions -d 'Install fish shell completions'
    
    # Add script-specific completions here
    EOF
    
        if [[ $? -eq 0 ]]; then
            echo "Fish completions installed to: $completions_file"
            echo ""
            echo "Completions will be available in new fish shell sessions."
            echo "To use them immediately in this session, run:"
            echo "  source $completions_file"
        else
            echo "Error: Failed to write completions file" >&2
            exit 1
        fi
    
        exit 0
    }
    
    usage() {
        echo "Usage: $SCRIPT_NAME [options]"
        echo ""
        echo "Description: What this script does"
        echo ""
        echo "Options:"
        echo "  -h, --help            Show this help message"
        echo "  -v, --version         Show version information"
        echo "  --test                Run unit and regression tests"
        echo "  --fish-completions    Install fish shell completions"
        exit 0
    }
    
    main() {
        log_info "action=start status=processing"
    
        # Your script logic here
        echo "Hello from example bash script!"
    
        log_info "action=complete status=success"
    }
    
    # Parse arguments
    while [[ $# -gt 0 ]]; do
        case $1 in
            -h|--help)
                usage
                ;;
            -v|--version)
                show_version
                ;;
            --test)
                run_tests
                ;;
            --fish-completions)
                install_fish_completions
                ;;
            *)
                echo "Unknown option: $1"
                usage
                ;;
        esac
        shift
    done
    
    log_debug "action=init args=\"$*\""
    main
    

    Enhanced Fish Template for Data-Processing Scripts

    For scripts that process input and produce output (especially multi-item processing), use this enhanced template:

    #!/usr/bin/env fish
    
    # Script: process-items
    # Version: 1.0.0
    # Description: Process items from input and output results
    # Installation: Copy to ~/bin/scripts
    
    set VERSION "1.0.0"
    set SCRIPT_NAME (basename (status filename))
    
    # Logging functions
    function log_info
        logger -t "$SCRIPT_NAME[$fish_pid]" -p user.info $argv
    end
    
    function log_error
        logger -t "$SCRIPT_NAME[$fish_pid]" -p user.error $argv
    end
    
    function show_version
        echo "$SCRIPT_NAME version $VERSION"
        exit 0
    end
    
    function usage
        echo "Usage: $SCRIPT_NAME [options] [input-file]"
        echo ""
        echo "Process items from input and output results."
        echo ""
        echo "Arguments:"
        echo "  input-file            File containing items (default: stdin)"
        echo ""
        echo "Options:"
        echo "  -h, --help            Show this help message"
        echo "  -v, --version         Show version information"
        echo "  -o, --output FILE     Output file (default: stdout)"
        echo "  -a, --append          Append to existing file instead of overwriting"
        echo "  --progress            Force progress updates (even in batch mode)"
        echo "  --no-progress         Suppress progress updates (even in interactive mode)"
        echo "  --test                Run unit and regression tests"
        echo "  --fish-completions    Install fish shell completions"
        echo ""
        echo "Examples:"
        echo "  $SCRIPT_NAME input.txt -o output.txt"
        echo "  cat input.txt | $SCRIPT_NAME"
        echo "  $SCRIPT_NAME input.txt | other-tool"
        exit 0
    end
    
    function main
        # I/O configuration
        set input_file "-"
        set output_file "-"
        set append_mode 0
    
        # Progress configuration (auto-detect TTY)
        set progress_mode 0
        if isatty stderr
            set progress_mode 1
        end
    
        # Parse arguments
        argparse 'h/help' 'v/version' 'o/output=' 'a/append' 'progress' 'no-progress' 'test' 'fish-completions' -- $argv
        or begin
            usage
            exit 2
        end
    
        # Handle flags
        if set -q _flag_help; usage; end
        if set -q _flag_version; show_version; end
        if set -q _flag_output; set output_file $_flag_output; end
        if set -q _flag_append; set append_mode 1; end
        if set -q _flag_progress; set progress_mode 1; end
        if set -q _flag_no_progress; set progress_mode 0; end
    
        # Get input file from remaining arguments
        if test (count $argv) -gt 0
            set input_file $argv[1]
            if test "$input_file" != "-" -a ! -f "$input_file"
                echo "Error: Input file not found: $input_file" >&2
                log_error "action=read_input status=not_found file=\"$input_file\""
                exit 2
            end
        end
    
        # Validate append requires output file
        if test $append_mode -eq 1 -a "$output_file" = "-"
            echo "Error: --append requires --output to specify a file" >&2
            exit 2
        end
    
        log_info "action=start input=\"$input_file\" output=\"$output_file\""
    
        # Read input items
        if test "$input_file" = "-"
            set items (cat)
        else
            set items (cat $input_file)
        end
    
        # Process items with progress
        set current 0
        set total (count $items)
        set results
    
        for item in $items
            set current (math $current + 1)
    
            # Show progress (non-scrolling, in-place update)
            if test $progress_mode -eq 1
                printf "\r[%d/%d] Processing: %s" $current $total "$item" >&2
            end
    
            # Process item (replace with actual logic)
            set result (process_item $item)
            set -a results $result
        end
    
        # Complete progress line
        if test $progress_mode -eq 1
            printf "\n" >&2
        end
    
        # Summary to stderr (always show)
        echo "Processed $total items" >&2
    
        # Write output (data to stdout or file)
        if test "$output_file" = "-"
            printf "%s\n" $results
        else
            if test $append_mode -eq 1
                printf "%s\n" $results >> "$output_file"
            else
                printf "%s\n" $results > "$output_file"
            end
        end
    
        log_info "action=complete status=success count=$total"
    end
    
    function process_item
        # Replace with actual processing logic
        echo "processed: $argv[1]"
    end
    
    # Run main
    main $argv
    

    Common Errors to Avoid

    NOTE: For Fish-specific errors (variable scoping, directory changes, stdin detection, etc.), see ~/fish-shell-rules.md which documents recurring bugs from this project's history.

    1. Mixing Data and Messages on stdout

    WRONG:

    echo "Processing file..."  # Goes to stdout
    echo "$result"              # Also goes to stdout
    

    CORRECT:

    echo "Processing file..." >&2  # Messages to stderr
    echo "$result"                 # Data to stdout
    

    2. Not Supporting stdin/stdout

    WRONG: Only accepting file arguments

    cat $argv[1]  # Fails if no file specified
    

    CORRECT: Default to stdin/stdout

    set input_file "-"
    if test (count $argv) -gt 0
        set input_file $argv[1]
    end
    

    3. Using Relative Paths After cd

    WRONG:

    cd /some/directory
    cat config.txt  # Where is this file now?
    

    CORRECT:

    # Store original directory or use absolute paths
    set origin_dir (pwd)
    cd /some/directory
    # ... work ...
    cd $origin_dir
    cat config.txt
    

    4. Not Checking Exit Codes

    WRONG:

    curl $url > data.json
    process_file data.json  # What if curl failed?
    

    CORRECT:

    curl $url > data.json
    if test $status -ne 0
        log_error "action=download status=failed url=\"$url\""
        exit 1
    end
    

    5. Silent Failures

    WRONG:

    if not command -v tool
        exit 1  # User has no idea what happened
    end
    

    CORRECT:

    if not command -v tool
        echo "Error: 'tool' is not installed" >&2
        echo "Install with: brew install tool" >&2
        log_error "action=dependency_check status=missing tool=tool"
        exit 3
    end
    

    6. Not Validating Flag Combinations

    WRONG: Allowing --append without --output

    # Should validate that append mode requires a file
    

    CORRECT:

    if test $append_mode -eq 1 -a "$output_file" = "-"
        echo "Error: --append requires --output to specify a file" >&2
        exit 2
    end
    

    7. Interactive Prompts in Pipeable Scripts

    WRONG: Asking for user input in a data-processing script

    read -P "Continue? (y/n): " answer
    

    CORRECT: Use flags for all options, avoid prompts in pipe-friendly scripts

    Troubleshooting

    • Script not found after install: Check PATH and restart shell or source config
    • Permission denied: Verify chmod +x was applied to the script
    • Command not found: Ensure ~/bin/scripts is in PATH
    • Git merge conflicts: If conflicts occur, resolve manually or abort with git merge --abort
    • Dirty git state: If repository has uncommitted changes, stash them first with git stash
    • Branch already exists: Delete the old branch with git branch -D add-<script-name> or use a different name

    Git Workflow Notes

    • Always work on a feature branch (never directly on main)
    • Each new script gets its own branch: add-<script-name>
    • MANDATORY: Always delete feature branches after merging - this is required, not optional
    • Clean branches keep the repository organized and prevent confusion about what's in progress
    • If you need to abandon a script, delete the branch without merging: git checkout main && git branch -D add-<script-name>

    Git Commit Message Standards

    IMPORTANT: Use detailed, structured commit messages with the following format:

    Add <script-name>: <brief one-line description>
    
    Features:
    - Feature 1 with details
    - Feature 2 with details
    - Feature 3 with details
    
    Technical details:
    - Implementation detail 1
    - Implementation detail 2
    - Configuration or dependency notes
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    

    Guidelines:

    • Subject line: Start with "Add :" followed by brief description
    • Features section: List all user-facing features and capabilities
    • Technical details section: Include implementation notes, technologies used, dependencies
    • Co-authorship: Always include AI assistance attribution
    • Use bullet points for clarity
    • Be specific about what was implemented
    • Include any important configuration or setup notes

    Example:

    Add backup-tool: Automated backup script with compression and rotation
    
    Features:
    - Automatic backup of specified directories
    - Gzip compression with configurable level
    - Rotation policy (keeps last N backups)
    - Email notifications on completion or failure
    - Dry-run mode for testing
    
    Technical details:
    - Implemented in Fish shell with structured logging
    - Uses rsync for efficient file copying
    - Logger integration for syslog monitoring
    - Configuration via environment variables
    - Requires: rsync, gzip, mail utilities
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    Repository
    bradreaves/chezmoi
    Files