Skip to main content
Contributions to bash::framehead are welcome! This guide covers the standards and workflow for submitting improvements.

Project principles

Keep these principles in mind when contributing:

Single file distribution

The compiled output must remain a single sourceable file with no installation required.

Modular architecture

Modules should have minimal coupling. Only runtime.sh is required by all modules.

Graceful degradation

Functions should check for dependencies and fail cleanly with helpful messages.

Consistent naming

All functions follow module::function convention. No exceptions.

Pure Bash preferred

Avoid external tools unless necessary. Document any dependencies clearly.

No side effects

Functions take input and return output. No global state mutation.

Getting started

1

Fork and clone

Fork the repository and clone your fork:
git clone https://github.com/YOUR_USERNAME/bash-framehead.git
cd bash-framehead
2

Compile the framework

Build the single-file output:
./main.sh compile
# → compiled.sh
3

Run tests

Verify everything works:
./main.sh test ./compiled.sh
All tests should pass before making changes.
4

Make your changes

Edit files in src/ or add new modules following the adding modules guide.
5

Recompile and test

./main.sh compile
./main.sh test ./compiled.sh
Ensure your changes don’t break existing functionality.

Code standards

Function naming

All public functions must follow module::function pattern:
# ✓ Correct
string::upper
math::factorial
fs::read
process::is_running

# ✗ Wrong  
str_upper
Factorial
readFile
isRunning
Internal helper functions should be prefixed with _:
# Internal helper
_string::normalize_whitespace() {
    # ...
}

# Public API
string::trim() {
    _string::normalize_whitespace "$1"
}

Documentation comments

Every public function needs documentation:
# Brief description of what the function does
# Usage: module::function arg1 arg2 [optional_arg]
# Example: module::function value1 value2
module::function() {
    # implementation
}
These comments are extracted by the wiki generator. Follow the format exactly for best results.

Error handling

Functions should fail gracefully with helpful messages:
# ✓ Good error handling
math::sqrt() {
    local n="$1"
    if ! math::has_bc; then
        echo "Error: bc required for math::sqrt" >&2
        return 1
    fi
    if [[ ! "$n" =~ ^[0-9]+\.?[0-9]*$ ]]; then
        echo "Error: math::sqrt requires numeric input" >&2
        return 1
    fi
    math::bc "sqrt($n)" "$MATH_SCALE"
}

# ✗ Bad error handling
math::sqrt() {
    bc <<< "sqrt($1)"  # Cryptic failure if bc missing or input invalid
}

Dependencies

Check for external dependencies at runtime:
# Check once and cache result
if ! runtime::has_command jq; then
    echo "Error: json::parse requires jq" >&2
    return 1
fi
Document dependencies in comments:
# Parse JSON string using jq
# Requires: jq
# Usage: json::parse json_string query
json::parse() {
    # ...
}

Testing requirements

All new functions must have test coverage:
1

Add tests to tester()

Add a new section or extend existing module tests in main.sh:
echo ""
echo "--- yourmodule ---"
_test "yourmodule::function" "expected" "$(yourmodule::function input)"
_test "yourmodule::edge_case" "0" "$( yourmodule::edge_case; echo $? )"
2

Test multiple scenarios

Cover normal cases, edge cases, and errors:
_test "string::index_of (found)"    "2"   "$(string::index_of hello l)"
_test "string::index_of (missing)"  "-1"  "$(string::index_of hello x)"
_test "string::index_of (empty)"    "-1"  "$(string::index_of '' a)"
3

Mark functions as tested

_mark_tested yourmodule::function yourmodule::edge_case
This prevents them from appearing in the “untested functions” report.
4

Verify test output

./main.sh test ./compiled.sh | grep yourmodule
All tests should show PASS.
See the Testing guide for comprehensive testing patterns.

ShellCheck compliance

The compiler runs ShellCheck automatically if available: From main.sh:42-62:
# Run shellcheck once, parse counts from output
local err_file=0 warn_file=0 info_file=0 issue_str_file=""
if $has_shellcheck; then
    local sc_out
    sc_out=$(shellcheck --format=gcc "$func_file" 2>/dev/null)
    err_file=$(echo "$sc_out"  | grep -c ': error:')
    warn_file=$(echo "$sc_out" | grep -c ': warning:')
    info_file=$(echo "$sc_out" | grep -c ': note:')

    # Also show human-readable output
    shellcheck --color=auto --format=tty "$func_file" 2>/dev/null || true

    local file_issues=$(( err_file + warn_file + info_file ))
    if (( file_issues > 0 )); then
        issue_str_file=" — $file_issues issues ($err_file errors, $warn_file warnings, $info_file info)"
        (( total_err  += err_file  ))
        (( total_warn += warn_file ))
        (( total_info += info_file ))
    fi
fi
Install ShellCheck for local validation:
# Ubuntu/Debian
sudo apt install shellcheck

# macOS
brew install shellcheck

# Check your code
shellcheck src/yourmodule.sh
Common ShellCheck issues to avoid:
# ✗ SC2086: Quote variables to prevent word splitting
cp $file $dest

# ✓ Correct
cp "$file" "$dest"

# ✗ SC2312: Useless use of cat
cat file.txt | grep pattern

# ✓ Correct  
grep pattern file.txt

# ✗ SC2155: Declare and assign separately
local result=$(command)

# ✓ Correct
local result
result=$(command)
Fix all ShellCheck errors before submitting. Warnings and info notes are acceptable if justified.

Pull request workflow

1

Create a feature branch

git checkout -b feature/your-feature-name
Use descriptive branch names:
  • feature/add-json-module
  • fix/string-trim-edge-case
  • docs/improve-math-examples
2

Make atomic commits

Commit related changes together:
git add src/yourmodule.sh
git commit -m "Add yourmodule with core functions"

git add main.sh  
git commit -m "Add tests for yourmodule"
Good commit messages:
  • “Add string::levenshtein distance function”
  • “Fix fs::path::join handling of absolute paths”
  • “Improve math::factorial performance for large inputs”
3

Update documentation

If you added functions, generate wiki pages:
./gen_wiki.sh ./compiled.sh ./wiki
git add wiki/
git commit -m "Generate wiki pages for yourmodule"
4

Push and create PR

git push origin feature/your-feature-name
Then create a pull request on GitHub with:
  • Clear description of changes
  • Test output showing all tests pass
  • Any relevant examples or use cases

PR checklist

Before submitting, ensure:
All functions follow module::function naming
ShellCheck passes with no errors
Code uses pure Bash where possible
Dependencies are checked at runtime
Error messages are helpful and descriptive
All public functions have doc comments
Comments include Usage and Example lines
Wiki pages generated for new functions
README updated if adding new module
All new functions have test coverage
Tests cover normal, edge, and error cases
All tests pass: ./main.sh test ./compiled.sh
Functions marked as tested with _mark_tested
Compilation succeeds: ./main.sh compile
No regression in existing tests
New module documented in main README if applicable

Types of contributions

New modules

Adding an entirely new module:
  1. Create src/newmodule.sh
  2. Implement functions following naming conventions
  3. Add comprehensive tests
  4. Generate wiki documentation
  5. Update main README with module description
See Adding modules for details.

New functions in existing modules

Extending an existing module:
  1. Add functions to appropriate src/module.sh file
  2. Follow existing code style in that module
  3. Add tests in the module’s test section
  4. Regenerate wiki pages

Bug fixes

Fixing issues:
  1. Add a test that reproduces the bug (should fail)
  2. Fix the bug
  3. Verify the test now passes
  4. Update documentation if behavior changed

Documentation improvements

Enhancing docs:
  1. Edit wiki pages directly (they won’t be overwritten)
  2. Add examples and use cases
  3. Clarify confusing explanations
  4. Fix typos and formatting

Performance improvements

Optimizing existing functions:
  1. Add benchmarks showing improvement
  2. Ensure tests still pass
  3. Document any behavior changes
  4. Consider backwards compatibility

Project structure

Understanding the layout:
bash-framehead/
├── main.sh               # Compiler, tester, statistics
├── src/                  # Module source files
   ├── runtime.sh       # Required base module
   ├── string.sh
   ├── array.sh
   └── ...
├── gen_wiki.sh          # Wiki documentation generator
├── compiled.sh          # Generated single-file output (gitignored)
├── wiki/                # Generated documentation
   ├── README.md
   ├── string.md
   └── string/*.md
├── README.md            # Main project README
└── LICENSE             # AGPL-3.0 license
The compiled.sh file is gitignored. Users compile it themselves from source.

License

Bash::framehead is licensed under AGPL-3.0. By contributing, you agree that your contributions will be licensed under the same license.

Code review process

After submitting a PR:
  1. Automated checks run (if configured)
  2. Maintainers review code quality and design
  3. Feedback provided via PR comments
  4. You address feedback with additional commits
  5. Once approved, PR is merged
Typical review timeline: 3-7 days for initial review.

Getting help

If you need help contributing:
  • Check existing issues on GitHub
  • Review the module adding guide
  • Look at existing modules as examples
  • Ask questions in issue discussions

Recognition

Contributors are recognized in:
  • Git commit history
  • GitHub contributors page
  • Release notes for significant contributions
Thank you for contributing to bash::framehead!

Next steps

Adding modules

Learn how to create new modules

Testing

Write comprehensive tests for your code

Wiki generation

Generate documentation from your code

Build docs developers (and LLMs) love