A pure-Go Bash 5.3 for Linux, macOS and Windows that also speaks Bash# — typed Go in shell text, fenced-language islands, and agentic blocks with contracts. Passes Bash's own 5.3 suite (86/86).
See the codebashy is one static binary — no CGo, no system bash — that is a drop-in
Bash 5.3 on Linux, macOS and Windows: same flags, same script semantics,
same $BASH_VERSION, and it passes GNU Bash's own 5.3 test suite (every
runnable fixture, 86/86). With --bashsharp the same binary speaks
Bash#: the bash you already know,
Go where you need types, any fenced language where you need a library, and
agentic where you need a model — with contracts so a model's output is
judged, never trusted.
Alpha (0.x). Bash 5.3 compatibility is stable; the Bash# dialect may still change before 1.0 through RFCs. Every number this project states names its corpus: docs/claims.md.
# macOS (Apple Silicon)
curl -fsSLO https://github.com/qiangli/bashy/releases/latest/download/bashy-darwin-arm64.tar.gz
tar -xzf bashy-darwin-arm64.tar.gz && sudo install bashy /usr/local/bin/bashy
bashy --version
Then take the tour — 27 small programs with pinned transcripts and one
script that runs them all on your machine, also written as a procedure your
coding agent can drive: bashsharp/tour.
The ten-minute version is in this repo: examples/quickstart/.
@guard(effects: "read")
@require('test -n "$1"')
@ensure('test "$1" != lie')
agentic function summarize() { ... }
agentic {
summarize ok # exit 0
summarize "" # exit 3 — precondition failed; the body never ran
summarize yield # exit 6 — "I need input": a yield, not a made-up answer
}
The interpreter never calls a model. agentic marks the one place a program
may hand work to one, and the contracts around it are ordinary shell
commands, run deterministically.
sh, or with --posix, it is a
POSIX shell: 493/493 on the licensed VSC shell arm, 99 %+ on yash's POSIX
suite (bash 5.3 itself scores 96 % there).ls, sed, awk, grep, find,
sort, tar, jq, git, make, … as applets, so the same script means
the same thing on Windows.readonly, contracts and agentic. Off with --no-bashsharp
or --posix, where none of it exists.PATH: bashy provisions what it uses — Go 1.27.1, zig cc
for C/C++, a uv-managed CPython, Node + typescript, a rustup toolchain —
downloaded from the vendor once, checksum-verified against a pin in this
repo, cached — so the same program means the same thing on every machine.
bashy check --prepare SCRIPT... pays that download ahead of time;
BASHPP_PYTHON, BASHPP_GO, BASHPP_CC, … name a program explicitly.bashy git clone, bashy scripts/bootstrap-siblings.sh,
bashy dag build — on Windows with no git, no Go and no C compiler on the
host (see From source).bashy check for static
checks, bashy dag for dependency-ordered tasks in Markdown, bashy awd
for "run this there", registered commands, and the agentic yield status
a harness can act on.Built on the qiangli/sh fork of
mvdan.cc/sh by Daniel Martí — the engine is
his; the Bash 5.3 conformance work and the Bash# dialect are carried in the
fork. Campaign identity, regression gates and the product sequence:
docs/internal/campaign-and-gates.md.
Grab the archive for your platform from the
Releases page and put bashy on
your PATH:
| Platform | Asset |
|---|---|
| Linux x86-64 | bashy-linux-amd64.tar.gz |
| Linux arm64 | bashy-linux-arm64.tar.gz |
| macOS Intel | bashy-darwin-amd64.tar.gz |
| macOS Apple Silicon | bashy-darwin-arm64.tar.gz |
| Windows x86-64 | bashy-windows-amd64.zip |
| Windows arm64 | bashy-windows-arm64.zip |
# Linux/macOS example
tar -xzf bashy-linux-amd64.tar.gz
sudo install bashy /usr/local/bin/bashy
bashy --version
go install github.com/qiangli/bashy@latest is not supported: the module
resolves its engine and siblings through flat replace ../<sibling>
directives, which go install refuses. Use a release archive above, or build
from source below.
bashy rebuilds itself using only an installed bashy. Every command below is
run through bashy, so the same five lines work on Linux, macOS and
Windows: bashy git fetches the sources, bashy scripts/bootstrap-siblings.sh
checks out the sibling modules at the exact SHAs in .sibling-pins, and
bashy dag build compiles both binaries through bashy go, which downloads
and verifies its own pinned Go toolchain into bashy's cache the first time.
bashy git clone https://github.com/qiangli/bashy
cd bashy
bashy scripts/bootstrap-siblings.sh
bashy dag build # -> bin/bash and bin/bashy (bin/*.exe on Windows)
bashy dag install # optional: install into ~/.local/bin ($DHNT_BIN_DIR to change)
What the host must provide, per platform:
| git | Go | C compiler | |
|---|---|---|---|
| Windows | none — bashy git downloads a pinned, checksum-verified MinGit | none — bashy go provisions it | not used |
| macOS | the system git (Xcode Command Line Tools: xcode-select --install) | none — bashy go provisions it | optional |
| Linux | the distribution's git | none — bashy go provisions it | optional |
The C compiler is optional on Linux and macOS: with cc on PATH the build
also compiles the native pre-Go signal launcher (bin/bashy + bin/bashy.real);
without one it says so and ships the plain Go binaries — the same form the
release archives ship. bashy git on Linux and macOS deliberately uses the
platform git rather than downloading one.
A checkout that has no installed bashy yet can bootstrap from the repo-local
launcher instead (Linux/macOS; it needs a host go):
./bashy dag build
./bashy dag install
The traditional host-tool path also works when git, go and make are
already installed:
git clone https://github.com/qiangli/bashy
cd bashy
./scripts/bootstrap-siblings.sh # clones each sibling next door at its pinned SHA
make build # -> bin/bash and bin/bashy
Bashy is all you need. With nothing but the release download — no git, go, podman or docker on the host — build the image and run your script with no network:
bashy self image
bashy podman run --rm --network=none -v "$PWD:/work" -w /work localhost/bashy:<ver>-linux-<arch> --bashsharp ./script.bsh
bashy self image fetches the release's static bashy-scratch-linux-<arch>
artifact (checksum-verified) and builds a FROM scratch image around it
through bashy podman — the engine bashy provisions for itself from the
pinned upstream releases (a complete static podman on Linux; the machine
client plus gvproxy/vfkit on macOS; the client on Windows, where the machine
runs on WSL2 — every edition). The image is bashy as it is: Bash 5.3, --posix,
Bash#, the builtin coreutils, dag/weave/check/transpile. What is and is not in
it, per command, is the measured matrix in
docs/airgap-image.md. From a checkout,
bashy dag build-image images the candidate instead of a published artifact.
A minimal Linux container base (Ubuntu/glibc, launcher + payload) is described
in docs/bashy-oci-base.md.
Real-repository examples driven by bashy dag — one dag.md each for
GitHub CLI, Hugo, Caddy, curl, git, FFmpeg, tesseract, llama.cpp, CMake, uv,
Codex, Bun, OpenCode, OpenClaw, Hermes Agent and more, calling their Go,
Python, TypeScript, Rust and C/C++ code as fenced islands — live under
examples/dag/.
bashy script.sh arg1 arg2 # run a script
bashy -c 'echo "$BASH_VERSION"'# run a command string
bashy # interactive shell
echo 'echo hi' | bashy # read a script from stdin
bashy accepts the common Bash invocation flags:
| Flag | Meaning |
|---|---|
-c <string> | run <string> as a command |
-i | force interactive mode |
-l, --login | act as a login shell |
--posix | POSIX mode |
--norc | do not read ~/.bashyrc |
--noprofile | do not read profile files |
--rcfile, --init-file <f> | use <f> as the interactive startup file |
-o <opt> | enable a set option (e.g. errexit, xtrace) |
-O <opt> | enable a shopt option |
--pretty-print | pretty-print the parsed input |
--version | print version and exit |
Invoked as bash or bashy, the shell starts in GNU Bash 5.3-compatible
mode. Invoked with basename sh, it starts in POSIX sh mode. POSIX mode can
also be requested with --posix, -o posix, SHELLOPTS=posix, or by the
presence of POSIXLY_CORRECT/POSIX_PEDANTIC (including empty values).
Command-line -o/+o posix is last-wins unless one of the environment or sh
startup conditions forces POSIX mode, matching GNU Bash 5.3.
The complete contract, including strict sh semantics and certification
wiring, is documented in Shell mode selection.
Startup files: interactive shells read ~/.bashyrc (or --rcfile); login
shells read /etc/profile and ~/.bashy_profile; $BASH_ENV is honoured for
non-interactive shells.
bashy is a pure-Go runner: subshells are goroutines rather than fork(),
and process substitutions use real named pipes. Job control
(jobs/fg/bg/kill %n/suspend with stopped-state tracking),
coprocesses, and signal traps are implemented and pass Bash's test suite on
Unix. Mirroring Bash's own design (jobs.c on Unix, nojobs.c elsewhere),
the OS-level job-control machinery is Unix-only; on other platforms it
degrades exactly as a no-job-control Bash does.
Two known gaps: arithmetic currently uses the native int width (64-bit on
64-bit platforms), so very large values on 32-bit builds truncate — a tracked
int64 migration; and some interactive job-control behavior remains incomplete.
The final Sprint 253 production gate measured the Bash 5.3 fixtures at
86/86 on Windows and Linux (run 35812307698), and the Sprint 257 timezone
follow-up measured 86/86 on two native Windows builds, native macOS, and
Ubuntu 24.04 test droplets. These are fixture results, not a claim of full
Bash compatibility; see the umbrella's docs/sprint-253-delivery-evidence.md.
Everything else — parameter expansion, arrays and associative arrays,
namerefs, [[ ]], arithmetic, here documents, brace/tilde/glob expansion
(locale-aware, including non-UTF-8 charsets such as Big5/Shift-JIS), traps,
printf, read, prompt escapes — matches Bash 5.3 and is verified against
Bash's own test suite.
See CLAUDE.md for the development workflow and docs/
for the compliance roadmap and per-fixture analyses. The Bash 5.3 suite is
driven by make test-bash (serial; needs a controlling terminal; make test-bash-fixtures fetches the pinned fixture tree). The language, its
roadmap and RFCs live in bashsharp/bashsharp.
BSD 3-Clause (inherited from mvdan.cc/sh). See LICENSE.
Go
79.5%
Shell
18.7%
A pure-Go Bash 5.3 for Linux, macOS and Windows that also speaks Bash# — typed Go in shell text, fenced-language islands, and agentic blocks with contracts. Passes Bash's own 5.3 suite (86/86).
See the codebashy is one static binary — no CGo, no system bash — that is a drop-in
Bash 5.3 on Linux, macOS and Windows: same flags, same script semantics,
same $BASH_VERSION, and it passes GNU Bash's own 5.3 test suite (every
runnable fixture, 86/86). With --bashsharp the same binary speaks
Bash#: the bash you already know,
Go where you need types, any fenced language where you need a library, and
agentic where you need a model — with contracts so a model's output is
judged, never trusted.
Alpha (0.x). Bash 5.3 compatibility is stable; the Bash# dialect may still change before 1.0 through RFCs. Every number this project states names its corpus: docs/claims.md.
# macOS (Apple Silicon)
curl -fsSLO https://github.com/qiangli/bashy/releases/latest/download/bashy-darwin-arm64.tar.gz
tar -xzf bashy-darwin-arm64.tar.gz && sudo install bashy /usr/local/bin/bashy
bashy --version
Then take the tour — 27 small programs with pinned transcripts and one
script that runs them all on your machine, also written as a procedure your
coding agent can drive: bashsharp/tour.
The ten-minute version is in this repo: examples/quickstart/.
@guard(effects: "read")
@require('test -n "$1"')
@ensure('test "$1" != lie')
agentic function summarize() { ... }
agentic {
summarize ok # exit 0
summarize "" # exit 3 — precondition failed; the body never ran
summarize yield # exit 6 — "I need input": a yield, not a made-up answer
}
The interpreter never calls a model. agentic marks the one place a program
may hand work to one, and the contracts around it are ordinary shell
commands, run deterministically.
sh, or with --posix, it is a
POSIX shell: 493/493 on the licensed VSC shell arm, 99 %+ on yash's POSIX
suite (bash 5.3 itself scores 96 % there).ls, sed, awk, grep, find,
sort, tar, jq, git, make, … as applets, so the same script means
the same thing on Windows.readonly, contracts and agentic. Off with --no-bashsharp
or --posix, where none of it exists.PATH: bashy provisions what it uses — Go 1.27.1, zig cc
for C/C++, a uv-managed CPython, Node + typescript, a rustup toolchain —
downloaded from the vendor once, checksum-verified against a pin in this
repo, cached — so the same program means the same thing on every machine.
bashy check --prepare SCRIPT... pays that download ahead of time;
BASHPP_PYTHON, BASHPP_GO, BASHPP_CC, … name a program explicitly.bashy git clone, bashy scripts/bootstrap-siblings.sh,
bashy dag build — on Windows with no git, no Go and no C compiler on the
host (see From source).bashy check for static
checks, bashy dag for dependency-ordered tasks in Markdown, bashy awd
for "run this there", registered commands, and the agentic yield status
a harness can act on.Built on the qiangli/sh fork of
mvdan.cc/sh by Daniel Martí — the engine is
his; the Bash 5.3 conformance work and the Bash# dialect are carried in the
fork. Campaign identity, regression gates and the product sequence:
docs/internal/campaign-and-gates.md.
Grab the archive for your platform from the
Releases page and put bashy on
your PATH:
| Platform | Asset |
|---|---|
| Linux x86-64 | bashy-linux-amd64.tar.gz |
| Linux arm64 | bashy-linux-arm64.tar.gz |
| macOS Intel | bashy-darwin-amd64.tar.gz |
| macOS Apple Silicon | bashy-darwin-arm64.tar.gz |
| Windows x86-64 | bashy-windows-amd64.zip |
| Windows arm64 | bashy-windows-arm64.zip |
# Linux/macOS example
tar -xzf bashy-linux-amd64.tar.gz
sudo install bashy /usr/local/bin/bashy
bashy --version
go install github.com/qiangli/bashy@latest is not supported: the module
resolves its engine and siblings through flat replace ../<sibling>
directives, which go install refuses. Use a release archive above, or build
from source below.
bashy rebuilds itself using only an installed bashy. Every command below is
run through bashy, so the same five lines work on Linux, macOS and
Windows: bashy git fetches the sources, bashy scripts/bootstrap-siblings.sh
checks out the sibling modules at the exact SHAs in .sibling-pins, and
bashy dag build compiles both binaries through bashy go, which downloads
and verifies its own pinned Go toolchain into bashy's cache the first time.
bashy git clone https://github.com/qiangli/bashy
cd bashy
bashy scripts/bootstrap-siblings.sh
bashy dag build # -> bin/bash and bin/bashy (bin/*.exe on Windows)
bashy dag install # optional: install into ~/.local/bin ($DHNT_BIN_DIR to change)
What the host must provide, per platform:
| git | Go | C compiler | |
|---|---|---|---|
| Windows | none — bashy git downloads a pinned, checksum-verified MinGit | none — bashy go provisions it | not used |
| macOS | the system git (Xcode Command Line Tools: xcode-select --install) | none — bashy go provisions it | optional |
| Linux | the distribution's git | none — bashy go provisions it | optional |
The C compiler is optional on Linux and macOS: with cc on PATH the build
also compiles the native pre-Go signal launcher (bin/bashy + bin/bashy.real);
without one it says so and ships the plain Go binaries — the same form the
release archives ship. bashy git on Linux and macOS deliberately uses the
platform git rather than downloading one.
A checkout that has no installed bashy yet can bootstrap from the repo-local
launcher instead (Linux/macOS; it needs a host go):
./bashy dag build
./bashy dag install
The traditional host-tool path also works when git, go and make are
already installed:
git clone https://github.com/qiangli/bashy
cd bashy
./scripts/bootstrap-siblings.sh # clones each sibling next door at its pinned SHA
make build # -> bin/bash and bin/bashy
Bashy is all you need. With nothing but the release download — no git, go, podman or docker on the host — build the image and run your script with no network:
bashy self image
bashy podman run --rm --network=none -v "$PWD:/work" -w /work localhost/bashy:<ver>-linux-<arch> --bashsharp ./script.bsh
bashy self image fetches the release's static bashy-scratch-linux-<arch>
artifact (checksum-verified) and builds a FROM scratch image around it
through bashy podman — the engine bashy provisions for itself from the
pinned upstream releases (a complete static podman on Linux; the machine
client plus gvproxy/vfkit on macOS; the client on Windows, where the machine
runs on WSL2 — every edition). The image is bashy as it is: Bash 5.3, --posix,
Bash#, the builtin coreutils, dag/weave/check/transpile. What is and is not in
it, per command, is the measured matrix in
docs/airgap-image.md. From a checkout,
bashy dag build-image images the candidate instead of a published artifact.
A minimal Linux container base (Ubuntu/glibc, launcher + payload) is described
in docs/bashy-oci-base.md.
Real-repository examples driven by bashy dag — one dag.md each for
GitHub CLI, Hugo, Caddy, curl, git, FFmpeg, tesseract, llama.cpp, CMake, uv,
Codex, Bun, OpenCode, OpenClaw, Hermes Agent and more, calling their Go,
Python, TypeScript, Rust and C/C++ code as fenced islands — live under
examples/dag/.
bashy script.sh arg1 arg2 # run a script
bashy -c 'echo "$BASH_VERSION"'# run a command string
bashy # interactive shell
echo 'echo hi' | bashy # read a script from stdin
bashy accepts the common Bash invocation flags:
| Flag | Meaning |
|---|---|
-c <string> | run <string> as a command |
-i | force interactive mode |
-l, --login | act as a login shell |
--posix | POSIX mode |
--norc | do not read ~/.bashyrc |
--noprofile | do not read profile files |
--rcfile, --init-file <f> | use <f> as the interactive startup file |
-o <opt> | enable a set option (e.g. errexit, xtrace) |
-O <opt> | enable a shopt option |
--pretty-print | pretty-print the parsed input |
--version | print version and exit |
Invoked as bash or bashy, the shell starts in GNU Bash 5.3-compatible
mode. Invoked with basename sh, it starts in POSIX sh mode. POSIX mode can
also be requested with --posix, -o posix, SHELLOPTS=posix, or by the
presence of POSIXLY_CORRECT/POSIX_PEDANTIC (including empty values).
Command-line -o/+o posix is last-wins unless one of the environment or sh
startup conditions forces POSIX mode, matching GNU Bash 5.3.
The complete contract, including strict sh semantics and certification
wiring, is documented in Shell mode selection.
Startup files: interactive shells read ~/.bashyrc (or --rcfile); login
shells read /etc/profile and ~/.bashy_profile; $BASH_ENV is honoured for
non-interactive shells.
bashy is a pure-Go runner: subshells are goroutines rather than fork(),
and process substitutions use real named pipes. Job control
(jobs/fg/bg/kill %n/suspend with stopped-state tracking),
coprocesses, and signal traps are implemented and pass Bash's test suite on
Unix. Mirroring Bash's own design (jobs.c on Unix, nojobs.c elsewhere),
the OS-level job-control machinery is Unix-only; on other platforms it
degrades exactly as a no-job-control Bash does.
Two known gaps: arithmetic currently uses the native int width (64-bit on
64-bit platforms), so very large values on 32-bit builds truncate — a tracked
int64 migration; and some interactive job-control behavior remains incomplete.
The final Sprint 253 production gate measured the Bash 5.3 fixtures at
86/86 on Windows and Linux (run 35812307698), and the Sprint 257 timezone
follow-up measured 86/86 on two native Windows builds, native macOS, and
Ubuntu 24.04 test droplets. These are fixture results, not a claim of full
Bash compatibility; see the umbrella's docs/sprint-253-delivery-evidence.md.
Everything else — parameter expansion, arrays and associative arrays,
namerefs, [[ ]], arithmetic, here documents, brace/tilde/glob expansion
(locale-aware, including non-UTF-8 charsets such as Big5/Shift-JIS), traps,
printf, read, prompt escapes — matches Bash 5.3 and is verified against
Bash's own test suite.
See CLAUDE.md for the development workflow and docs/
for the compliance roadmap and per-fixture analyses. The Bash 5.3 suite is
driven by make test-bash (serial; needs a controlling terminal; make test-bash-fixtures fetches the pinned fixture tree). The language, its
roadmap and RFCs live in bashsharp/bashsharp.
BSD 3-Clause (inherited from mvdan.cc/sh). See LICENSE.
Go
79.5%
Shell
18.7%