Native Shell
Native Shell은 모든 플랫폼의 앱 안에서 만들어지는 AI UI입니다
UNIXWIN은 Windows와 Linux와 macOS에서 진짜 bash를 쓴다
UNIXWIN:AI-native 的真·Bash 家族——niubash、WinuxCmd、rubash、niu-git、wpm。真 bash 语法、真 Unix 命令、原生 Windows / Linux / macOS,无 WSL、无 MSYS。83/83 GNU 套件全过、82 套逐字节一致、~14ms git 启动、3.79MB 单文件。
개발 도구Rust · PythonGitHub @unixwin온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
AI-native bash for humans and AI agents: real bash syntax, real Unix commands (winuxcmd), real git via niu-git (~14 ms startup vs Git Bash's 75-100 ms). Native Windows/Linux/macOS - no WSL, no MSYS, no POSIX emulation.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Real Bash, native on Windows, Linux, and macOS. 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.
Docs & downloads: unixwin.dev
Install · Niubash vs Git Bash · Why not Git Bash / MSYS2 / Cygwin · AI agents · Compatibility · Performance · Limitations
niubash is a Bash-compatible shell implemented natively in Rust — a Git Bash alternative. On Windows, the flagship platform, one niu.exe carries the whole stack:
git on PATH is the git binary — no MSYS runtime, no launcher hop, no bundled perl. Git's shell-script parts (hooks, git bisect, git mergetool) run on niubash's own sh.Agents launched from a niu session inherit it as their shell through SHELL; Coding agents on Windows documents, agent by agent, which shell each one 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. It is a from-scratch replacement for Git Bash: a native Windows binary. The full per-platform contract, including the honest status of every target, lives in platform-support.md.
The same commands, two outcomes — Git Bash's MSYS layer vs niu, side by side. Tap the image for the animated version (assets/demo-gitbash.gif).
All downloads start at unixwin.dev. Latest release: v1.5.0 (2026-11-03; the releases page always carries the newest build).
Windows via winget (1.5.0):
winget install --id Unixwin.Niubash
Windows via installer: 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 (tar -xf niubash-v*-win-x64.tar.gz, built into Windows 10+) — it restores the bundled git/awk payload's hardlinks on unpack, so the extracted tree stays as small as a wpm install. The .7z is the smallest download (solid compression), but it stores the duplicated payload content rather than links, so the extracted tree is larger. The .zip stays only for tooling that speaks nothing but zip: it cannot represent hardlinks, so the payload is stored duplicated and the archive is much larger.
Linux via apt (x86_64, aarch64; Ubuntu 22.04+, Debian 12+):
curl -fsSL https://unixwin.github.io/apt/KEY.gpg | sudo gpg --dearmor -o /usr/share/keyrings/niubash-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/niubash-archive-keyring.gpg] https://unixwin.github.io/apt stable main" | sudo tee /etc/apt/sources.list.d/niubash.list
sudo apt update && sudo apt install niubash
The archive follows releases automatically (picked up within hours of a release; gh workflow run build-apt -R unixwin/apt triggers the pickup immediately). It installs /usr/bin/niu only — your system bash and coreutils stay untouched.
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
Android (aarch64, armv7): release .zip assets ship since v1.4.3 and run on real devices (Termux) — see Platforms for the honest per-platform status.
From source (Rust 1.95+):
git clone https://github.com/unixwin/niubash.git && cd niubash && cargo build --release
On Windows, configuration is ONE file, ~/.niubashrc, in plain Bash syntax — the only startup file niu reads there. Login shells on Linux/macOS also read the GNU profile chain (/etc/profile, then the first of ~/.bash_profile → ~/.bash_login → ~/.profile), exactly as GNU bash does; ~/.bashrc is never sourced directly (run niu plugin migrate-rc --diff to see exactly what is worth carrying over) — start with Getting started.
$ niu --version
Niubash 1.5.0 — bash-compatible shell for Windows, Linux, macOS, and Android
rubash git 29bbf52481c3
winuxcmd WinuxCmd 1.2.1
$ niu -c 'echo $BASH_VERSION'
5.3.20(1)-release
--version names the exact engine and command-layer builds the binary carries, so "which build am I talking to" always has an answer on record — the property an agent's logs depend on (rubash#488).
Git Bash calls itself, verbatim, "a BASH emulation used to run Git from the command line" — an emulation built to run Git. The costs are structural. Console device redirects such as echo >/dev/tty fail outright with Invalid argument in its MSYS layer, where niubash matches GNU. Its bundled bash is on the 5.2 line, so bash 5.3's ${ cmd; } nofork substitution does not exist. Its prompt runs __git_ps1 — a git process — on every draw. niu's git segment asks your own git at most once per prompt pass (one bounded status --porcelain=v2 --branch query, 2 s timeout), and repaints within the pass reuse that result instead of spawning again (measured steady state inside a repository: 1.0 spawn per pass, p50 26 ms per pass; Windows, same machine). And a real Git for Windows install is ≈440 MB plus a 20 MB simulation DLL, versus niu at ≈16 MB with zero DLLs (project-measured, as of 2026-10-25).
MSYS2's own documentation concedes that arguments resembling Unix paths are automatically rewritten before being passed to native programs — and that the rewriting "isn't perfect," hitting arguments that aren't paths, or path lists that aren't. niubash keeps translation deliberately narrow: quoted arguments are never rewritten, and the only device translation is the exact token /dev/null → nul; every overreach ever found became a public issue and a pinned regression test.
Cygwin states on its own site that its core is a DLL providing POSIX API functionality, and that applications must be rebuilt from source to run in its world. The simulation layer is its official definition. niubash is a native build: no simulation DLL.
| Niubash | Git Bash | |
|---|---|---|
| Engine | Bash semantics reimplemented natively in Rust (rubash); no emulation layer | GNU Bash ported onto the MSYS2 POSIX emulation runtime |
| Bash language level | GNU Bash 5.3 semantics — including 5.3-only syntax such as no-fork command substitution ${ cmd; } (rubash#195) | GNU Bash 5.2 (the version Git for Windows bundles) |
| Path handling | Windows paths are the native representation; argument translation is a deterministic, documented contract — quoted arguments never rewritten, no guessing | Heuristic path conversion of arguments, with MSYS_NO_PATHCONV as the documented opt-out |
git | Real git-for-windows C source built with MSVC (niu-git) — the binary itself; no MSYS runtime, no launcher hop | git launched through the MSYS runtime |
| Prompt git segment | Your own git, at most once per prompt pass (bounded porcelain query); repaints reuse the result | Runs __git_ps1 — spawns git on every prompt |
| Subshells | In-process — ( ) and $( ) create no processes | fork() emulation |
| Console devices | /dev/tty redirects behave like GNU — the engine splits CON into CONIN$/CONOUT$ (see Quick answers) | Console device redirects fail outright in the MSYS layer |
| Install footprint | ≈16 MB, zero DLLs | ≈440 MB + 20 MB msys-2.0.dll (project-measured, real installs, as of 2026-10-25) |
The long version — including same-command-line side-by-sides of what actually reaches a native process — is Why niubash.
The bundled commands are WinuxCmd: 176 commands plus the 2 internal helpers wpm and [ — 178 applets, 1,924 options — native Windows builds, evolved in lockstep with this shell (repo); path forms, argument passing, and shell interplay are designed against shell semantics. The obvious alternative, Microsoft's own coreutils package, is an upstream uutils build packaged for PowerShell/CMD (its repo describes itself as "Installer & Packaging", and the package is in preview). Its README states its own limits: no /dev/null, no POSIX signals, kill and timeout not shipped, and twenty-plus commands — chmod, chown, id, tty, mkfifo, nohup, stty, … — dropped wholesale as "POSIX-only concepts". A command layer for a shell cannot start by discarding the concepts a shell lives on.
The new Rust shells sell lightness. Of the peers, hush is a Lua-based language that never claimed to replace bash, and Oils/OSH calls itself an "upgrade path from bash", not a drop-in. brush claims the drop-in: "Run it as your everyday shell", "Production-ready for most use cases". Measured with a 306-case differential corpus (byte-compared against GNU Bash 5.3.20): its shipped v0.4.0 scores 181/306, and a source build of its latest master commit re-measures at 183/306 — the same failure profile — against rubash's 304/306 on the same ruler. The misses are foundation mechanisms, not edge cases: an alias timing model reversed from GNU's (6 substantive divergences in 20 probes), printf x y looping forever and hanging the script in the release (fixed on master), wait $! unimplemented in scripts, globstar that does not recurse while listed as "Fully Supported", and nameref unset reporting "not yet implemented" — which a real oh-my-bash load trips over. Its Windows support is self-described "Preview", and v0.4.0 ships no Windows binary at all.
Lightweight is no excuse for missing limbs. Complete bash semantics re-implemented path by path without fork, plus cross-platform itself, is what 373,267 net lines (rubash 312,965 + niubash 60,302; tests excluded, the code-size caliber of the rubash README, measured 2026-11-03) buys. An implementation that misses these mechanisms can be neither a bash replacement nor a reliable login shell.
Models are trained on Bash; on a Windows machine their commands deserve a shell that executes them the way they were written.
Agents inherit niu as their shell. Anything launched from a niu session gets it through SHELL, and Coding agents on Windows documents, agent by agent, which shell each one runs and how to point the rest at niu.
--ec: stop quoting commands, base64 them instead. An agent's command passes through several hosts before it reaches the shell — and every one of them can break nested quotes, expand $, or eat backslashes. niu accepts the whole command as one base64 string, so there is simply nothing left to escape:
# the command you want to run:
# git log -1 --format="commit %h on %cd" --date="format:%Y-%m-%d"
# base64 it — one line in any language — and hand niu the string:
$ niu --ec Z2l0IGxvZyAtMSAtLWZvcm1hdD0iY29tbWl0ICVoIG9uICVjZCIgLS1kYXRlPSJmb3JtYXQ6JVktJW0tJWQi
commit 58e10d1 on 2026-11-02
Same output as typing the command by hand — but the agent never wrote a single quote. (Captured in the niubash checkout, 2026-11-04.) PowerShell users already know this shape: -EncodedCommand, spelled the same way and case-insensitive (--ec is the short alias). The decoder accepts wrapped lines, missing padding, and an optional v1: prefix that guards the payload through Git-Bash-style layers. Full cookbook for Python / Node / Rust / PowerShell — encoders, the failure modes this removes, payload limits — in Coding agents on Windows.
Wiring a tool to niu? The integration is a one-line change where the command line gets built — wherever the code assembles ["-c", cmd], it assembles ["--ec", b64] instead:
use base64::engine::general_purpose::STANDARD as B64;
use base64::Engine as _;
// before — the command travels as raw argv; any layer that re-quotes,
// expands, or truncates it breaks the call
c.args(["-c", command]);
// after — base64 in, the command bytes reach niu verbatim
c.args(["--ec", &B64.encode(command.as_bytes())]);
The swap is the same shape in every host language. Shell flags keep working in front of the payload: niu -eu -o pipefail --ec <b64> runs the decoded command under errexit and pipefail.
Real agent usage came first. OpenCode users run niu.exe as their agent's shell and drove the environment-driven init work (); a Hermes integration failure — literal quotes leaking into external-command arguments — was filed and fixed (); and after three false-baseline incidents in a single day, now carries build metadata, so an agent can always tell exactly which build it is talking to ( — shown under above).
The casualty list that motivates this — real agent failures on PowerShell and emulation shells, with receipts — is in Why niubash.
niu's language semantics are the rubash engine's, and they are gated mechanically, not anecdotally:
tests/compat.rs, tests/host_contract.rs, and the per-capability fixtures in the compatibility matrix).As of 2026-11-03 the trackers carry the receipts: rubash 1,680 issues filed / 1,654 closed; niubash 449 filed / 425 closed.
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 — plus 72 in the small buckets: 54 syntax forms rubash still rejects where GNU accepts, 17 early exits, 1 error storm. The full log is committed (eco-harvest.py, eco-test.py, snapshot wt92-local-20261005).
Framework assets are sourced and timed. 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.json carries a measured budget (healthy themes re-render in 11–35 ms and the budget line is 120 ms on the Windows reference baseline; 5× 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.
Every number below comes from one published protocol — the 2026-10-25 baseline (PERF-BASELINE-2026-10-25, in the public shellbench repo): release builds, Linux, against a self-built GNU Bash 5.3.20.
The honest headline. The embedded rubash engine pays a roughly uniform ~3× floor tax on interpreter-bound micro-work (arithmetic, function calls, assignment, read loops at 2.8–3.2× per-op). Beating GNU across the full table is the stated goal — the standing hard target of the post-1.5.0 programme; the current status is published, not hidden. Where the cost is process creation, the model inverts: pipeline stages and command substitution run in-process, at 0.05× (pipe) and 0.11× (command-substitution loop) of GNU's time.
Startup — the one quotable set. -c 'true', p50 of 50 interleaved samples, release builds, Linux: niu 3.96 ms, rubash 3.43 ms, GNU Bash 5.3.20 2.59 ms. No Windows startup figures are quoted until re-measured on real Windows hardware under the same protocol.
Windows process economics. A console-less session used to pay a hidden-console allocation on every external spawn. The fix is one hidden console per session — pre-allocated windowless on Windows 11 24H2+/Server 2025, adopted from the first CREATE_NO_WINDOW child elsewhere — pinned by 14 regression tests (design in #462, landed engine-side in rubash#913). And $(tput …) terminal queries are answered in-process for admitted TERM×capability shapes, byte-equal to GNU ncurses on a 269-row differential matrix, with zero spawns (rubash#884).
Loop scripts — one Windows machine, measured. Same-machine Windows measurement (niubash 1.4.4): a 50-iteration loop over a sed|grep|awk pipeline — 150 external command launches in total — takes 1.502s in niubash and 27.256s in Git Bash, roughly 18×. The gap is not in the commands; it is Windows process-startup cost: no fork, no POSIX emulation layer, a startup surface more than an order of magnitude smaller. Original record: niubash #567.
Android, stated plainly. An on-device Android baseline exists (#352); its engine-side root causes were found and closed (rubash#607–#609), fork-bound workloads already ran faster there, and a post-fix on-device re-measure is still owed — we say so instead of quoting the stale pre-fix numbers.
| 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 | apt repo (stable), portable .tar.gz, uses system tools |
| macOS aarch64 / x86_64 | Released; smoke-gated every release | portable .tar.gz, uses system tools |
| Android aarch64 / armv7 | Shipped since v1.4.3; runs on real devices (Termux), release smoke gate not yet wired in CI | NDK-linked .zip release asset |
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 also blocks on the golden user journey and the per-asset timing budget gates. OpenHarmony has not passed that gate (compile-checked only, never run on a device). Android ships release .zip assets since v1.4.3 and runs on real devices (Termux aarch64/armv7, daily-driven with on-device benchmark baselines); what it lacks is the automated per-release smoke leg in CI, which is wired for Windows/Linux/macOS only. The per-platform contract and the full status matrix live in platform-support.md.
/mnt/c..zip assets since v1.4.3, running on real devices). OpenHarmony (aarch64) builds in CI and has no release yet.echo >/dev/tty, exec 3<>/dev/tty, and test -e /dev/tty all behave like GNU — the engine maps /dev/tty to the console and splits CON into its CONIN$/CONOUT$ halves instead of hitting Windows' device-open restrictions (FILE_APPEND_DATA and read-write opens are rejected on CON). This is what keeps git/ssh askpass prompts working. (Engine trail: rubash#1312, rubash#1314, niubash#519.).zip assets ship since v1.4.3 and run on real devices (Termux aarch64/armv7). HarmonyOS not yet: it compiles in CI but has no installable artifact.Docs site · Why niubash (the long version, with the agent casualties) · Platform support · Bash compatibility matrix · Roadmap
On the engine side, 1.5.0 lands the embeddable engine API (rubash#595) and a native script debugger — rubash --debug for humans and --dap for editors, two front ends over one debug session (rubash#497).
If niu saved you a Linux VM, a mangled quote, or an argument PowerShell ate, star the repo and tell a developer. ★
Thanks to everyone building niubash — issues, fixes, plugins, adapted work, and engine work upstream (emoji key):
MIT. See LICENSE.
--versionDeterministic non-interactive behavior. niu -c and script runs are quiet and stable: no banners, stable stdout/stderr, exact exit-code propagation — the properties an agent's tool loop depends on.
No path roulette. There is no MSYS_NO_PATHCONV to remember and no heuristic rewriting arguments behind the child's back — /flags stay /flags, and path-shaped operands are translated by one documented contract (windows-path-contract.md).