> Real Bash, native on Windows, Linux, and macOS. "Windows-only" is the
> old story: five platforms build from this tree now, and Windows remains
> the flagship — no WSL. No VM. No /mnt/c. No cmdlet dialect. One binary:
> the shell your fingers already know, and the one your AI agent actually
> speaks.
niubash is a Bash-compatible shell implemented natively in Rust. On
Windows, the flagship platform, one niu.exe bundles everything: the
rubash language engine, real Unix
commands from winuxcmd, a git-aware
prompt, and a permission-modeled plugin system. Git comes from
niu-git: the real git-for-windows C
source built with MSVC, so the git on PATH is the git binary — no MSYS
runtime, no launcher hop, no bundled perl. git --version starts in ~14
ms (13.7 ms avg / 11.5 ms min measured; git status 22.6 ms) where Git
Bash's git takes 45-103 ms
(niu-git#12,
niubash#374), and the
shell-script parts of
git (hooks, git bisect, git mergetool) run on niubash's own sh. Agents
launched from a niu session inherit it as their shell through SHELL; see
Coding agents on Windows for which shell each agent runs
and how to point the rest at niu. The
Linux and macOS builds
are portable niu binaries that use your system's own tools. niu is not
MSYS2, Cygwin, Git Bash, or WSL — there is no POSIX emulation layer and no
path-conversion heuristics. The full per-platform contract, including the
honest status of every target, lives in
platform-support.md.
| Platform | Status | Ships as |
|---|
| Windows x64 / ARM64 | Released; smoke-gated every release | installer .exe + portable .tar.gz/.7z/.zip, Unix commands bundled |
| Linux x86_64 / aarch64 (glibc 2.35+) | Released; smoke-gated every release | portable .tar.gz, uses system tools |
| macOS aarch64 / x86_64 | Released; smoke-gated every release | portable .tar.gz, uses system tools |
| Android aarch64 / armv7 | CI build only, no release | NDK-linked zip on workflow runs, not smoke-tested |
OpenHarmony (aarch64-unknown-linux-ohos) | CI check only, no release | kept compiling by CI, never run on a device |
"Smoke-gated" means the artifact is built, then run on its own OS against
four checks (--version, -c execution, a pipeline through native
coreutils, the offline plugin stack) before upload — the gate lives in
release.yml ("no smoke, no artifact": Linux legs run it natively on
ubuntu-22.04/ubuntu-22.04-arm, the macOS x86_64 leg under Rosetta 2),
and the release as a whole additionally blocks on the golden user journey
and the per-asset timing budget gates. Android and OpenHarmony have not
passed that gate: Android artifacts are build- and link-verified only (an
ELF shape check, explicitly not a runtime smoke), OpenHarmony is
compile-checked only, and neither claims device readiness. The
per-platform contract and the full status matrix live in
platform-support.md.
Quick answers:
- Does niu require WSL? No. niu is a native build on every platform it
ships for: on Windows there is no Linux VM, no emulation layer, no
/mnt/c.
- What platforms does niu run on? Released builds cover Windows (x64,
ARM64), Linux (x86_64, aarch64; glibc 2.35+), and macOS (aarch64,
x86_64). Android (aarch64, armv7) and OpenHarmony (aarch64) build in CI
and have no release yet; Android additionally carries a measured
performance baseline (see Performance).
- Does niu run real Bash scripts? Yes. The rubash engine is gated on
GNU Bash's own upstream test suites; the record lives in the
compatibility matrix.
- Can I install niu on Android or HarmonyOS today? Not yet. Both
targets compile in CI, neither has passed a runtime smoke test, so there
is nothing to install.
Receipts
Each claim below links to the artifact that produced it: a committed log, a
baseline file, a CI gate.
6,336 real-world shell assets, harvested and replayed one by one. The
pipeline pulls shell scripts, frameworks, themes, and dotfiles from GitHub
and sources each one under niu, recording a per-asset verdict: 4,891 OK,
350 slow, 224 that GNU Bash also fails, 101 hangs, 698 that never fetched.
The full log is committed
(eco-harvest.py,
eco-test.py, snapshot
wt92-local-20261005).
Framework assets are sourced and timed, not just "supported." The
timing baseline loads 437 real oh-my-bash and bash-it assets (166 themes
plus plugins, completions, aliases) and measures three phases per asset
(source, first prompt, re-render) as a median of three runs. That includes
the nvm assets of both frameworks, and real users' dotfiles that load
nvm.sh go through the same harness with per-phase timings on record
(baseline,
snapshot).
A release cannot ship slow. Every asset in
budgets.toml carries a measured budget
(healthy themes re-render in 11-35 ms; the budget line is 120 ms; 5x over
budget is a hard fail). The
release pipeline runs the perfbudget
gate and fails the release on a breach; a nightly run watches the trend.
The GNU Bash upstream golden-suite record lives with the engine: the
rubash README carries the
ledger (83/83 upstream suites on the 2026-10-12 full re-run), and rubash
CI replays the upstream corpus on Linux on every push (the "Bash upstream
test progress" job, scripts/run-bash-upstream-tests.sh).
Every number below is pinned to the issue or PR that measured it, and the
tests or gates that keep it honest are named.
Windows spawn cost — one hidden console per session, not per child. A
console-less session (direct niu -c, detached, CI) used to pay a hidden
console allocation on every external spawn, ~22 ms per child (design and
shape in niubash#462).
The fix landed engine-side
(rubash#913): a windowless
console is pre-allocated once on Windows 11 24H2+/Server 2025
(AllocConsoleWithOptions), or adopted from the first CREATE_NO_WINDOW
child (AttachConsole) on older builds, so an entire niu -c 'a; b; c'
tree pays at most one allocation and later spawns inherit it. 14
regression tests pin zero visible windows and the scaling behavior
(rubash tests/console_window_gate.rs).
$(tput …) terminal queries answered in-process. The inline tput
whitelist arm (rubash#884)
answers admitted TERM×capability shapes in-process, byte-equal to GNU
ncurses (269-row differential matrix, diff = 0; 8 regression tests). On
the ticket probe — 64 tput calls through command substitution — wall time
fell 1165 ms → 47 ms (~25x, zero spawns). The winuxcmd-side twin removed
the ~17 ms per-call i18n overhead in the real binary (~0.4 ms in-process
after the fix; 3208-row replay byte-identical:
WinuxCmd#1269). The other
harvest SLOW face — read on EOF, ~4.8 s/call — is still open on
rubash#800.
Engine hot paths (the embedded rubash
engine; each fix carries its measured delta and GNU differential battery):
- Multi-word literal command fast path:
[ 1 -eq 2 ] ×20k ≈177→155 ms
(rubash#967).
[[ ]] direct numeric leaf + decimal fast path: 50k [[ 1 -eq 2 ]]
1.41x→1.10x vs GNU
(rubash#966).
- Whitelist-skip of the procsub metadata scan: 1.56x→1.39x (~11%)
(rubash#974).
- Decimal-subscript array write lane: interleaved 8k 3.65x→3.16x; also
fixes a real double side-effect in
a[$((i++))]=v
(rubash#959).
- Case: head-only
$BASH_COMMAND render: 20-arm ×10k −10%, plus the
divergence fix (rubash#958).
The interpreter triage behind that wave is closed with numbers: scalar
assignment ~1.06x GNU (rubash#609 → #672/#678), arithmetic loops and
parameter expansion via rubash#607/#608 (#665/#671/#679, #666), and the
O(n²) array element write became O(1) amortized (rubash#618/#616:
associative 5000-key writes 445x→9.9x vs GNU, indexed 736x→3.8x; the
ledger lives in rubash's docs/performance.md). The export/unset
fast-lane family has landed (#917/#918/#920, reworked for correctness in
#943); rubash#916 stays
open on the residual.
Android baseline — measured, honest, not yet re-measured. On a Termux
aarch64 tablet, niubash 1.4.0 vs GNU bash 5.3.20
(niubash#352, full
method and matrix in the issue): interpreter-bound workloads 2.3-3.7x
slower (up to 7.3x on ${x^^} itself), niu -c true 21.1 ms vs bash's
8.3 ms (median of 30), peak RSS 2.2x — while fork-bound workloads run up
to 5.2x faster and a real mkdir/write/read-back script 2.1x faster. The
engine-side root causes were fixed and closed (rubash#607-609) and the
wrapper's one-shot startup gap closed too
(niubash#351:
niu -c true 15 ms vs bash 13 ms after the fix, zero tput spawns).
niubash#349 is the
original ~2.1x arithmetic/function datapoint. No post-fix re-measure on
Android hardware exists yet — #352 stays open for that re-run, and the
Android leg still ships build-verified only.
Quick start
All downloads start at unixwin.dev.
Windows: grab niubash-v*-win-*-setup.exe from
Releases and run it — no
admin rights; PATH and a Windows Terminal profile are set up for you.
Prefer portable? Take the .tar.gz — it ships the bundled git/awk payload
as real hardlinks, so it downloads and unpacks much smaller than the .zip
(tar -xf niubash-v*-win-x64.tar.gz, built into Windows 10+). The .zip
stays for tooling that only speaks zip.
Linux (x86_64, aarch64; glibc 2.35+) and macOS (aarch64, x86_64): take the
portable tarball, untar, run:
tar -xzf niubash-v*-linux-x86_64.tar.gz && niubash-v*-linux-x86_64/niu
From source (Rust 1.95+):
git clone https://github.com/unixwin/niubash.git && cd niubash && cargo build --release
Configuration is one file, ~/.niubashrc, in plain Bash syntax — start
with Getting started.
Documentation
Docs site ·
Why niubash (the long version, with the agent
casualties) · Platform support ·
Bash compatibility matrix ·
Roadmap
If niu saved you a Linux VM, a mangled quote, or an argument PowerShell
ate, star the repo and tell a
developer. ★
License
MIT. See LICENSE.