gbash

Contributing

This page covers the repository structure, build process, and release workflow. For the full contributing guide, see CONTRIBUTING.md on GitHub.

Repository structure

The repo is a committed Go workspace plus a pnpm workspace.

  • Root module (./) -- public gbash package, CLI (cmd/gbash/), internal runtime, and core commands
  • contrib/ -- optional modules (awk, htmltomarkdown, jq, sqlite3, yq, extras, nodejs) kept separate to avoid pulling optional dependencies into the core import graph
  • examples/ -- standalone example projects (separate Go module)
  • packages/ -- publishable JavaScript packages, including @ewhauser/gbash-wasm
  • website/ -- documentation site

Key internal packages:

PackagePurpose
internal/runtimeSession lifecycle, execution, budget enforcement
internal/shellProject-owned shell AST parsing, expansion, and execution
commandsBuilt-in command implementations
fsFilesystem interface and backends (memory, overlay)
policyPath checks, command allowlists, limits
networkHTTP client with allowlist enforcement
traceStructured execution event recording

Building and testing

make build    # build all Go modules
make test     # run tests across all modules
make lint     # run linters

For JavaScript workspace dependencies:

pnpm install --frozen-lockfile

To preview the website locally with the latest published compatibility data:

make website-dev

Module versioning

The repo uses go.work for local development with 9 modules (root + 8 children):

.                        contrib/awk              contrib/extras
contrib/htmltomarkdown   contrib/jq               contrib/nodejs
contrib/sqlite3          contrib/yq               examples

Published versions are coordinated. The root module uses plain tags such as vX.Y.Z; contrib modules use nested-module tags such as contrib/jq/vX.Y.Z. Child modules maintain real version requirements in go.mod plus local replace directives for development.

To prepare a coordinated release across all modules:

make fix-modules MODULE_VERSION=vX.Y.Z

This updates nested module requirements, refreshes local replaces, updates the npm package version, and runs go mod tidy in each child module.

Release process

Releases are driven by GitHub Actions:

  1. Run make release or dispatch the Prepare Release workflow
  2. Review and merge the generated release/vX.Y.Z PR into main
  3. The Publish Release workflow creates root and contrib tags, publishes the GitHub release with gbash and gbash-extras archives plus a shared checksum file

The prepare step derives the next version by incrementing the patch number of the latest root v* tag.

Benchmarks

Run comparison benchmarks locally:

make bench-compare
make bench-compare JSON_OUT=bench-compare.json  # JSON output
make bench-fs
make bench-fs BENCH_FS_JSON_OUT=/tmp/filesystem-bench.json

The benchmark compares five runtimes: native gbash, GNU bash, gbash-extras, gbash-node-wasm (WASM in Node.js), and just-bash (npm).

Some scenarios require optional commands such as jq. Those scenarios keep the full runtime table on the website, but unsupported runtimes are shown as skipped with a reason instead of being counted as failures.

GNU compatibility testing

Evaluate skew between gbash commands and GNU coreutils using the compatibility harness:

make gnu-test
make gnu-test GNU_UTILS="printf pwd"  # test specific utilities

The harness runs inside a Docker container. By default it pulls a published compat image from GitHub Container Registry, falling back to a local build if unavailable.