bash2yaml
Requires Python 3.11 or newer.
Compile pure Bash scripts into your CI/CD YAML. Get IDE support for your scripts while keeping them centralized.
Tired of writing Bash inside YAML strings with no syntax highlighting, linting, or testing? bash2yaml lets you
develop your CI logic in .sh files and then compiles them into your CI/CD configuration, giving you the
best of both worlds.
Supported targets: GitLab CI, GitHub Actions, CircleCI, AWS CodeBuild, Bitbucket Pipelines, and Semaphore CI.
Bash in YAML is Bash without quality gates. Also, includes support for inlining a large number of scripts from other language, from Python to PHP.
Before
Surely Gitlab has a solution for this? Not as far as I can tell. Here are some of my best workarounds.
Your IDE sees a single YAML string, and your scripts are trapped in one file.
.gitlab-ci.yml:
build-job:
script:
- echo "Building project"
- make build
After
Your IDE provides full support for Bash, and your scripts can be versioned, shared, and tested independently.
scripts/build.sh:
#!/usr/bin/env bash
set -eo pipefail
echo "Building project"
make build
uncompiled.gitlab-ci.yml:
build-job:
script:
- ./scripts/build.sh
Run bash2yaml compile, and the final, valid .gitlab-ci.yml is generated for you.
Who is this for?
This tool is for you if:
- You manage CI/CD templates in a centralized repository and
include:them in many other projects. - Your
.gitlab-ci.ymlfiles contain thousands of lines of shell scripts. - You want to write, test, and debug your CI scripts locally without involving Docker or a full pipeline simulation.
- Your IDE's lack of Bash support in YAML files is slowing you down.
- You want to be able to put Python or other non-Bash scripts into your shared templates.
If your CI/CD configuration is simple or contained entirely within a single repository, you might not need this tool.
Installation
bash2yaml is a standalone command-line tool. Installation with pipx is recommended to avoid dependency conflicts.
Install [all] for every optional feature, [fast] for native speedups only, or [pure-python-features] for the
optional command/UI stack without native extensions. The deprecated [bitrab] extra remains as a compatibility alias.
On your build server you can still install plain bash2yaml for the core compile/decompile flow to minimize supply
chain risk.
# Recommended
pipx install bash2yaml[all]
pipx install bash2yaml[fast]
# Or via pip
pip install bash2yaml[all]
pip install bash2yaml[pure-python-features]
Getting Started: A Quick Tour
-
Initialize Your Project Run
bash2yaml initto create a configuration file (.bash2yaml.toml) and directories to organize your source files. -
Decompile an Existing Configuration If you have an existing
.gitlab-ci.ymlwith inline scripts, you can extract them automatically:
bash2yaml decompile --in-file .gitlab-ci.yml --out my-project/
- Write and Edit Your Scripts
Create or edit your
.shfiles in thescriptsdirectory. Write standard, clean Bash—your IDE will thank you. In your source YAML (uncompiled.yml):
my-job:
script:
- ./scripts/my-script.sh
- Compile Compile your source YAML and scripts into a final, GitLab-ready configuration:
bash2yaml compile --in my-project/ --out compiled/
This generates a compiled/.gitlab-ci.yml file, ready to be deployed to your project's root.
Usage and Commands
bash2yaml provides a few core commands to manage your workflow.
Run with
- bash2yaml for CLI
- bash2yaml-interactive for CLI question and answer
- bash2yaml-tui for Terminal UI
- bash2yaml-gui for GUI
Core Compile/Decompile
| Command | Description |
|---|---|
compile |
Compiles source YAML and .sh files into final CI/CD YAML for your target. |
decompile |
Extracts inline scripts from CI/CD YAML into separate .sh files. |
Debugging from remote repo
| Command | Description |
|---|---|
copy2local |
Copies compiled files from a central repo to a local project for testing. |
map-deploy |
Copies compiled files from a central repo to a many local project for testing. |
commit-map |
Copies intential changes in local projects back to the central repo. |
Setup
| Command | Description |
|---|---|
init |
Initializes a new bash2yaml project and config file. |
clean |
Carefully delete output in target folder. |
install-precommit |
Add git hook to compile before commit |
uninstall-precommit |
Remove precommit hook |
Diagnostics
| Command | Description |
|---|---|
lint |
Call GitLab APIs to lint your YAML |
detect-drift |
Report what unexpected changes were made to the generated files. |
show-config |
Display config after cascade |
doctor |
Look for environment problems |
detect-uncompiled |
Detect if you forgot to compile |
validate |
Validate JSON schema of all YAML in input and output |
Other
| Command | Description |
|---|---|
check-pins |
Analyze GitLab CI include: statements and suggest pinning to tags |
trigger-pipelines |
Trigger pipelines in GitLab projects and optionally wait for completion |
autogit |
Manually trigger autogit process (stage, commit, and/or push changes) |
upgrade |
Upgrade bash2yaml using your current install method |
check-updates |
Check whether bash2yaml or its direct dependencies have upgrades |
For detailed options on any command, run bash2yaml <command> --help.
Advanced Topics
Bash Completion
Enable tab completion in your shell by running the global activation command once:
activate-global-python-argcomplete
Global Variables
To define variables that should be inlined into the global variables: block of your .gitlab-ci.yml, create a
global_variables.sh file in your input directory.
Limitations
- No
include:Inlining: This tool only inlines.shfile references. It does not process or merge GitLab'sinclude:statements for other YAML files. - Single Statement Invocations: The script invocation must be on its own line. Multi-statement lines like
echo "hello" && script.share not supported. - Comments: Comments in the source YAML may not be preserved in the final compiled output.
How It Compares
- gitlab-ci-local: This is an excellent tool for running your entire
GitLab pipeline in local Docker containers.
bash2yamlis different—it focuses on the "unit testing" of your Bash logic itself, assuming you can and want to execute your scripts on your local machine without the overhead of Docker. - **GitHub Actions ** GitHub composite actions do not have this problem. A shared GitHub action can reference a script in the shared action's repo. A GitHub "reusable" workflow is a single yaml file and might suffer from the same problem as Gitlab pipelines.
- Git Submodules Build runners will need permissions to clone and git is more complicated to use.
- Base image holds all bash You can only have one base image, so if you are using it for bash and yaml, you can't use other base images.
- Trigger remote pipeline A remote pipeline has access to the shell files in its own repo.
Project Health & Info
| Metric | Health | Metric | Info |
|---|---|---|---|
| Tests | License | ||
| Coverage | PyPI | ||
| Lint / Pre-commit | Python Versions | ||
| Quality Gate | Docs | ||
| CI Build | Downloads | ||
| Maintainability | Last Commit |
| Category | Health |
|---|---|
| Open Issues | |
| Stars |
Project Links
Metadata
Release files for bash2yaml 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| bash2yaml-1.0.0.tar.gz | 308.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| bash2yaml-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 540.8 kB
Release files / bash2yaml-1.0.0.tar.gz
| Download URL | bash2yaml-1.0.0.tar.gz |
|---|---|
| Size | 308.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7df89c3e1df1501b1670f8d227a63f850e8156e18490fb55e87ec3645c2ea6f5
|
|
BLAKE2b-256 checksum How to use checksums |
0a69a07ccfc534e94da1db46fe80d3f827854dfbc3d2043b696e10b580c4ddcc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.
Transparency logRelease files / bash2yaml-1.0.0-py3-none-any.whl
| Download URL | bash2yaml-1.0.0-py3-none-any.whl |
|---|---|
| Size | 232.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3de3fe3b0743ad30ededeeb4d5a2700df9709f80fa5685aa8b258e6449e487a0
|
|
BLAKE2b-256 checksum How to use checksums |
ab2f50b574999b9bd7d91df59a0a6ba1764843411d7b2d2da5c978dcd35848bf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.
Transparency log