Deterministic GNU-first shell toolchain inspired by the Google Shell Style Guide, with CI-safe workflows and an interactive toolchain shell.
Reference: Google Shell Style Guide.
shellgAIde is a pun that sounds like shellguide:
- shell: the domain (bash, portable scripts)
- gAIde: a “guide” powered by AI, inspired by the Google Shell Style Guide
- G = Google (explicitly referencing the style guide)
- AI = the assistant that generates scripts
- de = deterministic environment (the key promise of this repo)
make setup # installs deps (apt/brew) and writes .toolchain/env.sh
make shell # opens the toolchain shell (prompt shows [toolchain <version>])
make ci # check + lint + tests (inside the toolchain shell)make shell
make cimake ci-only # non-interactive, installs deps and runs checks
YES=1is only meant for setup/align (to auto-consent prompts).ci-onlyis designed to be non-interactive and should not requireYES=1.
Note:
makeis configured with--no-print-directoryfor uniform output across Linux and macOS. Tip:make shellopens an interactive Bash subshell with a prompt prefix like[toolchain x.y.z]so you always know you're inside the toolchain environment.
Use this when you want a safe, explicit toolchain context with a clear prompt marker:
- You always see:
[toolchain x.y.z] ... exitalways returns you to your original shell (no ambiguity)- No need to remember anything else after setup
Typical flow:
make setup
make shell
make ciUse this when you specifically need the GNU-first PATH in your current shell session (no subshell), for example:
- running
sed/grep/date/findmanually in your current terminal on macOS - IDE tasks / VS Code tasks that execute in your existing shell session
- scripting in your own shell where you don't want to open a separate Bash
Example:
make setup
source .toolchain/env.sh
make ciNote:
sourcemodifies only the current shell session; open a new terminal and you'd need to source again. On macOS, you must source the environment aftermake alignbefore runningmake check(unless you usemake shell).
This repo includes a complete custom agent for GitHub Copilot and other AI assistants.
Built-in custom agent for VS Code, JetBrains, and Visual Studio:
The agent is pre-configured in .github/copilot-instructions.md and automatically activates when working with *.sh files.
This repo also includes an archetype-style setup:
- Instructions: .github/instructions/shellgaide-gnu-bash.instructions.md
- Prompt (targets the agent): .github/prompts/shellgaide-generate-gnu-bash-script.prompt.md
Usage:
# In Copilot Chat:
"Create a script that processes log files"
"Refactor this to be GNU-first compliant"
"Explain the violations in this script"
Reference examples: .github/copilot-examples/
Technical details: .github/copilot-agent-spec.md
For ChatGPT, Codex CLI, Gemini, Claude, and configuration details, see:
- Local docs: docs/ai-config.md
- Published page: https://fragolinux.github.io/shellgAIde/ai-config.html
After generating/refactoring a script (locally):
make setup
# then inside the toolchain shell:
make lint
make test
make ciFor a single script:
make shell
# then:
./bin/lint.sh path/to/script.sh-
No BSD/GNU compromises
- Scripts assume GNU tools (
grep,sed,date,find,xargs). - macOS must be aligned via bootstrap.
- Scripts do NOT implement compatibility branches.
- Scripts assume GNU tools (
-
Fail fast
- If the environment is not aligned, scripts must fail with actionable instructions.
-
One mental entrypoint
- Everything is driven via
make.
- Everything is driven via
-
Automation > discipline
- Rules are enforced by tooling, not by memory.
.
├── bin/
│ ├── bootstrap.sh # environment check + alignment
│ ├── ci_only.sh # unattended CI gate (align + check + lint + test)
│ ├── lint.sh # shell linting & structural enforcement
│ ├── shell.sh # interactive toolchain shell wrapper
│ └── test.sh # bats test runner
├── lib/
│ └── common.sh # shared helpers
├── config/
│ └── toolchain.conf # version + policy
├── tests/
│ ├── fixtures/ # known-good / known-bad samples
│ └── *.bats # regression tests
├── PROMPT_SYSTEM.md # system prompt for AI tools
└── Makefile
make helpmake check- Returns
0if aligned - Returns
10if not aligned (expected on macOS initially)
make alignThis will:
- Install GNU tools (macOS via Homebrew)
- Install Bash 5.x, ShellCheck, shfmt, bats
- Generate
.toolchain/env.sh
.toolchain/env.sh to activate GNU-first PATH.
make lint LINT_PATH=.
make lint LINT_PATH=scripts/What lint does:
- Verifies Google-style structure (shebang, header, main)
- Runs ShellCheck (hard gate)
- Runs shfmt in diff mode
- Fails on any violation
make testmake ci LINT_PATH=.Equivalent to:
bootstrap checklinttest
All scripts MUST:
- Use GNU tools
- Use Bash >= 5.x
- Start with the standard header
- Use
main() - End with
main "$@"
If a script passes:
make ci…it is considered production-acceptable.
- Toolchain versions are explicit (
toolchain.conf). - New versions should:
- Extend rules, never weaken them
- Add tests to prevent regressions
- Bump version and regenerate zip
If a script:
- works on one machine but not another
- relies on implicit PATH behavior
- requires human memory to stay correct
…it is considered broken by design.
This toolchain exists to prevent that class of failure.
Use:
make ci-onlyThis target is designed for CI runners and will perform unattended alignment on macOS.
This repo includes a Pages workflow that publishes docs/ to GitHub Pages.
- Enable Pages in repo settings (Actions-based deployment or Pages from workflow).
- After pushing to
main, the site will be available underhttps://<owner>.github.io/<repo>/.
source .toolchain/env.sh is intended to be safe in interactive shells (bash and zsh). The generated env file does not enable shell options like nounset to avoid breaking zsh prompts.
If you prefer not to modify your current shell state, use:
make shellThis means your PATH does not contain a bash executable when scripts run via #!/usr/bin/env bash.
Fix:
- Run
make align - Activate the environment:
source .toolchain/env.sh - Verify:
command -v bash bash --version | head -n 1
On macOS, the toolchain expects Homebrew Bash (>= 5.x) to be found first on PATH.
Make targets invoke toolchain scripts via bash explicitly to avoid any edge cases with shebang resolution (#!/usr/bin/env bash) in unusual PATH environments.
By default, linting ignores the generated .toolchain/ directory. Use LINT_PATH=... to lint specific locations.
By default, make lint checks the whole repository (LINT_PATH defaults to .). Override it for a single file or directory:
make lint LINT_PATH=path/to/script.shIf you want to avoid large terminal diffs, enable artifact mode:
make lint LINT_ARTIFACTS=1This saves outputs under .toolchain/reports/lint-<timestamp>/ (gitignored), including:
shellcheck.txtshfmt.patchsnapshot.patch(if snapshot mode is enabled)
If you want a formatted baseline without touching your working tree:
make lint LINT_SNAPSHOT=1This creates a copy under .toolchain/snapshots/lint-<timestamp>/ and runs lint against the snapshot.
Combine with artifact mode to produce a patch you can apply:
make lint LINT_SNAPSHOT=1 LINT_ARTIFACTS=1Note:
make shellshows a[toolchain x.y.z]prompt prefix and will not start a nested toolchain shell if you're already inside one (TOOLCHAIN_SHELL=1).