Winuxsh

Bash, native on Windows. No WSL. No VM. No /mnt/c. No cmdlet dialect. Just the shell your fingers already know — and the one your AI agent actually speaks.

This is the Winuxsh documentation. Start with the guides, or jump straight into the shell:

C:\Users\you\repo
❯ test -f Cargo.toml && echo "rust, obviously"
rust, obviously

❯ printf "%s\n" alpha beta gamma | grep beta
beta

❯ cd "C:\Program Files"
C:\Program Files

What Winuxsh is

  • Bash syntax. if, for, case, $(...), pipes, redirects, heredocs, functions, aliases — the whole grammar, powered by rubash, which passes the GNU Bash project's own test suite (86/86 upstream tests green).
  • Windows-native. One binary, one process. Native Windows paths (C:\... and C:/...), direct execution of git.exe, node.exe, cargo.exe, python.exe — no VM, no emulation layer, no path conversion roulette.
  • Unix commands included. WinuxCmd ships ls, cat, grep, find, test, printf, and friends as Windows command links, with no separate installation.
  • AI-native. winuxsh -c is a contract: no banners, stable stdout/stderr, exact exit-code propagation. What an agent writes is what the process receives — the quoting roulette of PowerShell and the path mangling of MSYS/Git Bash are both gone.
  • A prompt you'll enjoy. 27 bundled themes (agnoster, spaceship, pure, catppuccin-mocha, tokyonight, p10 family, ...), a git prompt that grows teeth inside any repository, syntax highlighting, autosuggestions, vi and emacs modes, and Ctrl+R history search.
  • Plugins with a permission model. 40+ bundled packs (git, docker, kubectl, npm, zoxide, direnv, fzf, thefuck, ...), with reviewed source packs and process adapters declaring the host access they need.

The documentation

GuideWhat it covers
Getting StartedZero to a git prompt in ten minutes
Advanced UsageExecution modes, startup files, themes, plugins, completion, debugging
Install & Self-UpdateInstaller, portable zip, Windows Terminal profile, updates
Bash Compatibility MatrixWhat Bash surface is verified, layer by layer
Architecturerubash + WinuxCmd + reedline, path model, host contract
Windows Path Contractlogical root, dispatcher selection, and layer ownership
RoadmapWhat is done, what is next

Get it

Download the installer from GitHub Releases, or build from source:

git clone https://github.com/unixwin/winuxsh.git
cd winuxsh
cargo build --release
target\release\winuxsh.exe

Keep it current with winuxsh --self-update (or self-update inside the shell) and wpm update winuxcmd for the Unix command set. Questions and bug reports go to github.com/unixwin/winuxsh/issues.

Shell semantics live upstream in rubash — fix the engine, and every Bash user on Windows wins.

Why Winuxsh

The long version of the pitch. The README sells it in five seconds; this page shows the receipts.

The Windows shell civil war

Every Windows developer knows the tabs open on their machine:

OptionThe fine print
CMDFrozen in 1987. Your company's docs still paste it.
PowerShellA genuinely powerful automation language. It is not Bash — your for loops, grep, and quoting instincts die on arrival.
WSLA whole Linux distribution as a hobby you didn't sign up for. Boot a VM to print a directory. Dock your Docker Desktop's memory. Greet /mnt/c/Users/you/....
Git Bash / MSYS2Brilliant emulation with a cost: it translates, mangles, and converts your paths at the worst possible moments, and every git pays an emulation tax.

The treaty

Winuxsh is one native Windows binary that runs Bash syntax on Windows paths with real Windows programs — and brings the Unix commands Windows never had (ls, cat, grep, find, test, printf, ...).

WinuxshWSLGit BashPowerShell
Bash syntax
Native Windows paths (C:\..., no /mnt/c)⚠️ conversion quirks
Calls git.exe / node.exe directly⚠️ via /mnt/c⚠️ path translation
Unix commands (ls, grep, find)
Cold start to prompt~170 msseconds~1 s~280 ms
No extra OS, no VM
Themes, git prompt, plugins⚠️

One binary. One process. No distro to patch, no emulation layer to appease.

PowerShell eats arguments

Windows itself is the root cause: the platform has no argv array. Every executable receives a single command-line string and parses it with its own rules — and PowerShell adds a second parser on top. That's how PowerShell/PowerShell#1995 ("Arguments for external executables aren't correctly escaped") became a household name, and how dotnet/runtime#23347 opens by citing "the ongoing quoting woes PowerShell experiences."

Same command line, two shells. Watch what actually reaches the process:

# PowerShell 5.1                                # Winuxsh
> node -e "console.log(JSON.stringify(          ❯ node -e "console.log(JSON.stringify(
    process.argv.slice(1)))" "a b" "" "c\"d"      process.argv.slice(1)))" "a b" "" "c\"d"
    "e\f" "---"                                   "e\f" "---"

ParserError: TerminatorExpectedAtEndOfString   ["a b","","c\"d","e\\f","---"]

That command is written the way any model trained on Bash would write it. PowerShell throws a parse error before the process even starts. And when you quote it PowerShell's own way, the damage is quieter but still real: five arguments in, two mangled ones out — the empty string vanishes, the embedded quote is flattened, the last two arguments fuse into one:

> node -e "console.log(JSON.stringify(process.argv.slice(1)))" "a b" "" 'c"d' "e\f" "---"
["a b","cd e\\f ---"]

Agent casualties, with receipts

For humans this is a nuisance. For AI agents it's a minefield: models are trained on Bash, their quoting instincts are Bash-shaped, and on a PowerShell machine every generated command is a roll of the dice.

The path philosophy: native in, native out

Windows-native binaries don't speak the MSYS dialect. Here is Git Bash, in the wild, failing at exactly the things Winuxsh does without thinking:

Git Bash failing: backslash paths eaten, /c/ paths rejected by cmd, MSYS path conversion breaking git grep

What just happened, command by command:

CommandIn Git Bash (MSYS)In Winuxsh
node -e "..." "C:\Users\you\repo"the backslashes are eaten — the argument vanishesargument arrives byte-for-byte
cmd /c dir /c/Windows/...cmd.exe rejects the MSYS path (exit 1)native path, native tools, no guessing
git grep "/fn main"MSYS rewrites /fn into a Windows path — the pattern silently dies/ is just a character, not a path to convert

MSYS "solves" paths by guessing: it heuristically rewrites /c/foo into C:\foo, and famously mangles innocent arguments along the way — the notorious case of git grep "/pattern" silently becoming git grep "C:\...\pattern" is why MSYS2 still ships MSYS2_ARG_CONV_EXCL as an escape hatch. Every native tool call is a game of path roulette.

Winuxsh is the only Windows shell that doesn't translate anything — because it speaks both dialects itself and hands every process its own native language:

❯ cd /c/Users/you/repo     # MSYS-style input: understood
C:/Users/you/repo            # output: always Windows-native
❯ node -e "console.log(process.cwd())"
C:\Users\you\repo            # native binaries get native cwd
❯ cd "C:\Program Files"     # Windows-style input: understood
❯ pwd
C:/Program Files

Input in any dialect. Output always native. Zero guessing, zero conversion roulette — for your fingers, and for your agent.

Getting Started with Winuxsh

A short walkthrough from zero to a working prompt with git status.

1. Build or download

git clone https://github.com/unixwin/winuxsh.git
cd winuxsh
cargo build --release

After building, the binary is at target\release\winuxsh.exe. You can run it directly, or add target\release to your user PATH using your normal Windows environment settings:

target/release/winuxsh.exe

If you are using the release zip, winuxsh automatically runs the activation script on first start when command links are missing:

winuxsh winuxcmd/activate-winuxcmd.sh

That creates local command links inside winuxcmd/, so ls, cat, and friends resolve normally. Once the links exist, startup skips activation.

2. Start the shell

winuxsh

You should see something like:

user@DESKTOP C:\Users\you
%

Type exit or press Ctrl+D to quit.

3. See the git prompt

cd into any git repository:

cd C:\Users\you\repo
# if inside a repo, the prompt changes:
user@DESKTOP C:\Users\you\repo  git:(main) ●1 ✚2 ?1
%

Symbols at a glance:

SymbolMeaning
●NN files staged for commit
✚NN files modified but unstaged
?NN untracked files
↑NN commits ahead of upstream
↓NN commits behind upstream
⚑NN stashes saved
✖NN merge conflicts

The branch name is green when the tree is clean, yellow when dirty.

4. Try some commands

pwd                                  # prints C:/Users/you/repo
ls -la                               # Unix-style listing
echo "hello from $USER"
for i in 1 2 3; do echo $i; done
if [ -f Cargo.toml ]; then echo "yep"; fi
cat Cargo.toml | grep name
grep -n "fn main" src/main.rs

Windows paths work directly:

ls C:\Windows\System32\drivers\etc
ls D:/Projects
cd "C:\Program Files"

Multiline blocks work naturally:

for f in *.toml; do
  echo "found $f"
done

5. Try git completions

git ad<Tab>                # completes to `git add`
git commit -<Tab>           # shows flags: --message, --all, --amend
git push --fo<Tab>          # completes to --force
git branch -<Tab>           # shows -d, -D, -m, -v, -a, -r

6. Set up your config

Create ~/.winuxshrc for interactive shell code, plugin selection, and theme selection:

WINUXSH_THEME=minimal
WINUXSH_THEME_PLUGIN=theme-minimal
WINUXSH_PROMPT_SYMBOL="❯"
export WINUXSH_THEME WINUXSH_THEME_PLUGIN WINUXSH_PROMPT_SYMBOL

WINUXSH_PLUGINS=(prompt-core git)

if [ -z "${HOME:-}" ] && [ -n "${USERPROFILE:-}" ]; then
  HOME="$USERPROFILE"
  export HOME
fi

if [ -z "${WINUXSH:-}" ]; then
  WINUXSH="$HOME/.oh-my-winuxsh"
  export WINUXSH
fi

[ -f "$WINUXSH/oh-my-winuxsh.winux" ] && . "$WINUXSH/oh-my-winuxsh.winux"
winuxsh_prompt_use_template "{cwd} {git_prompt}{prompt_char} " "{time} " 2>/dev/null || true

export EDITOR=vim
alias ll='ls -la'
alias la='ls -a'
alias gst='git status'
alias gco='git checkout'
alias gl='git log --oneline --graph --decorate --all'

hello() {
  echo "hello from winuxsh"
}

~/.winuxshrc is sourced only for the interactive REPL and the -C one-shot REPL command path. It does not run for winuxsh -c ..., script files, or stdin script execution, so agent and CI surfaces stay deterministic.

~/.winshrc is a legacy compatibility fallback and is used only when ~/.winuxshrc is absent. Plugin CLI enable/disable records, migration blocks, completion overrides, test isolation, and advanced machine state are managed internally. Prefer ~/.winuxshrc for normal interactive customization.

6b. Prompt and theme plugins

Themes are official plugins. To use a Powerlevel-style theme, switch the theme plugin in ~/.winuxshrc:

WINUXSH_THEME=p10-lean
WINUXSH_THEME_PLUGIN=theme-p10-lean
WINUXSH_PLUGINS=(prompt-core git)

Useful bundled theme plugins include theme-minimal, theme-classic, theme-pure, theme-robbyrussell, theme-p10-lean, theme-p10-classic, theme-p10-rainbow, and theme-p10-pure. Theme assets support named colours, 256-colour indexes, and true-colour #RRGGBB foreground/background values plus bold, italic, underline, and dimmed flags.

Prompt templates use the public prompt-core API:

winuxsh_prompt_use_template "{cwd} {git}{prompt_char} " "{status}{time} "

Available template tokens include {cwd}, {cwd_base}, {user_host}, {git}, {git_prompt}, {status}, {time}, {command_execution_time}, {newline}, and {prompt_char}. The Git prompt snapshot is refreshed during startup/precmd so late Git work warms the next prompt instead of redrawing the line the user is typing on.

7. Official plugin bundle

Winuxsh has a built-in plugin system. oh-my-winuxsh is the official bundled plugin distribution. It ships first-party packs such as git, docker, kubectl, npm, zoxide, direnv, dotenv, fzf, prompt presets, and keybinding presets.

The normal interactive shape is the ~/.winuxshrc plugin list shown above. winuxsh plugin enable/disable and migration tooling update internal managed state. Official shell helper packs can ship reviewed bundle-local init.winux source scripts. If ~/.winuxshrc exists, it is the source-plugin entry point and loads the framework directly. Without ~/.winuxshrc, managed startup can still load enabled source packs before fallback ~/.winshrc. Use winuxsh plugin list, winuxsh plugin search, winuxsh plugin themes, and winuxsh plugin review for current inventory, theme sources, and permission checks.

What next

Advanced Winuxsh Usage

This guide covers the surfaces that matter after the first successful launch: execution modes, startup files, prompt/theme plugins, command discovery, and update/debug workflows.

For first-time setup, start with Getting Started.

Execution Modes

Winuxsh has three intentionally different execution paths:

winuxsh                         # interactive REPL
winuxsh -c 'pwd; echo "$SHELL"'  # quiet script/CI command mode
winuxsh -C 'alias ll; pwd'       # one-shot REPL command
  • Use the interactive REPL for normal shell work.
  • Use -c for scripts, tests, CI, and coding agents. It does not load ~/.winuxshrc, ~/.winshrc, prompt plugins, or interactive lifecycle hooks.
  • Use -C only when a one-shot command needs the same startup state as the interactive REPL. It loads ~/.winuxshrc and lifecycle hooks, then exits.

This separation keeps automation deterministic while still allowing a rich interactive shell.

Startup And Config

Use ~/.winuxshrc as the normal human-authored entry point:

WINUXSH_THEME=p10-classic
WINUXSH_THEME_PLUGIN=theme-p10-classic
WINUXSH_PROMPT_SYMBOL=">"
export WINUXSH_THEME WINUXSH_THEME_PLUGIN WINUXSH_PROMPT_SYMBOL

WINUXSH_PLUGINS=(prompt-core git common-aliases path-tools extract)

[ -f "$WINUXSH/oh-my-winuxsh.winux" ] && . "$WINUXSH/oh-my-winuxsh.winux"

alias ll='ls -la'
export EDITOR=vim

The legacy files still exist, but they should not be the primary user path:

  • ~/.winshrc is a fallback only when ~/.winuxshrc is absent.
  • Plugin CLI records, migration blocks, bundle versions, tests, and advanced overrides are internal managed state, not a user configuration file.

Do not put automation-critical behavior only in an interactive rc file. Pass needed environment variables directly to winuxsh -c or the script process.

Prompt And Themes

Prompt behavior is plugin-owned. The core shell provides host APIs and lifecycle hooks; official theme and prompt behavior lives in bundled plugins.

Common rc shape:

WINUXSH_THEME=p10-lean
WINUXSH_THEME_PLUGIN=theme-p10-lean
WINUXSH_PLUGINS=(prompt-core git)
export WINUXSH_THEME WINUXSH_THEME_PLUGIN

[ -f "$WINUXSH/oh-my-winuxsh.winux" ] && . "$WINUXSH/oh-my-winuxsh.winux"
winuxsh_prompt_use_template "{cwd} {git_prompt}{prompt_char} " "{status}{time} " 2>/dev/null || true

Theme assets can use named colors, 256-color indexes, and true-color #RRGGBB foreground/background values. Prefer changing the theme plugin or theme asset instead of hardcoding prompt rendering in shell core.

Git Prompt Performance

Git status should be consumed as a coherent prompt snapshot, not rendered by blocking every prompt draw with fresh Git processes. The intended shape is:

  • prompt/theme plugins render the latest available snapshot;
  • the host keeps git status work warm in the background;
  • late git work updates the next prompt instead of repainting the active input line.

If the prompt flickers or repaints the current line, debug the lifecycle and git snapshot path rather than adding more inline Git calls to the theme.

Plugin Workflow

Use the CLI to inspect the active bundle instead of relying on stale docs:

winuxsh plugin list
winuxsh plugin search git
winuxsh plugin themes
winuxsh plugin info git
winuxsh plugin review git
winuxsh plugin doctor

Normal interactive choices belong in ~/.winuxshrc:

WINUXSH_PLUGINS=(prompt-core git docker kubectl zoxide)
WINUXSH_THEME_PLUGIN=theme-p10-rainbow

Use managed plugin CLI operations when you need a reviewable machine record, permissions, bundle update state, or rollback.

Command Discovery And WPM

Winuxsh resolves Unix-style commands through normal Windows PATH. When a command is missing or comes from the wrong provider, inspect the active installation:

command -v winuxsh
command -v winuxcmd.exe
command -v ls
winuxcmd.exe wpm index status
winuxcmd.exe wpm search jq
winuxcmd.exe wpm links rebuild --force

Do not assume /usr/bin exists. Winuxsh is a Windows process using Windows executables and command links.

Windows Paths And Home

Prefer durable Windows paths in scripts:

cd C:/Users/you/repo
ls "C:\Program Files"
cd ~

Prompt display should normally render the home directory as ~ and descendants as ~/path, but internal process paths remain native Windows paths. Treat /c/Users/... as compatibility input, not the primary model.

Updating

Keep the three update planes separate:

winuxsh --self-update --check
winuxsh --self-update

winuxcmd.exe wpm update winuxcmd

winuxsh plugin update oh-my-winuxsh --github-release latest
winuxsh plugin rollback oh-my-winuxsh
  • winuxsh --self-update updates the shell.
  • wpm update winuxcmd updates command packages and command links.
  • plugin update oh-my-winuxsh updates the official plugin bundle.

Debug Checklist

For shell issues, capture the active binary and execution path first:

winuxsh --version
command -v winuxsh
command -v winuxcmd.exe
echo "$SHELL"
winuxsh -c 'echo command-mode:$SHELL'
winuxsh -C 'echo repl-command:$SHELL'

For repository changes, run focused tests before broad suites:

cargo test --test repl_command --locked
cargo test -p winuxsh-runtime --lib --locked
cargo test --test plugin_inventory --locked

Use Plugin System Direction for architecture and Plugin System Roadmap for execution order.

Installer and Self-Update

Winuxsh ships two Windows package shapes:

  • winuxsh-v<version>-win-<arch>-setup.exe for normal users.
  • winuxsh-v<version>-win-<arch>.zip for portable, agent, or scripted use.

The installer is built with Inno Setup and installs per user by default under:

%LOCALAPPDATA%\Programs\Winuxsh

It does not require administrator privileges. The default installer tasks:

  • add the install directory to the user's PATH;
  • add or update a Windows Terminal profile named Winuxsh;
  • set that profile's command line to the installed winuxsh.exe;
  • set that profile's starting directory to %USERPROFILE%;
  • point the Windows Terminal profile icon at the installed PNG asset.

The Windows Terminal profile is installed by running:

winuxsh --install-wt-profile --quiet

Users can run this command again after moving an install. To also set Winuxsh as the Windows Terminal default profile, run:

winuxsh --install-wt-profile --set-default

Self-update uses Windows WinHTTP directly to follow the GitHub Release releases/latest redirect, download the latest installer for the current architecture, and start it silently. It does not depend on the GitHub REST API.

winuxsh --self-update

Inside an interactive Winuxsh REPL, use:

self-update

The REPL command hands the update to a child process and exits the current shell so the installer can replace winuxsh.exe.

Useful dry-run modes:

winuxsh --self-update --check
winuxsh --self-update --dry-run

Interactive shells check for updates at most once per day. The check is best-effort and silent on network failures; when a newer release exists, Winuxsh prints a short hint to run self-update in the REPL or winuxsh --self-update outside it. Set WINUXSH_UPDATE_CHECK=0 or WINUXSH_NO_UPDATE_CHECK=1 to disable the reminder.

The installer invokes winuxcmd.exe wpm links rebuild --root ... --force after copying the files, so the bundled commands are materialized immediately. On NTFS, WPM creates hard links to the installed winuxcmd.exe. The portable zip keeps the first-start fallback: if command links are missing, Winuxsh runs winuxcmd/activate-winuxcmd.sh once from the bundle.

Updating WinuxCmd with WPM

The Unix command set (ls, cat, grep, sed, ...) is delivered by WinuxCmd and managed separately from the Winuxsh binary. Winux Package Manager (wpm) handles it:

wpm update winuxcmd          # update WinuxCmd from the local index
wpm index status             # inspect the local index state
wpm list                     # indexed packages and install state

wpm update winuxcmd refreshes the command set in place; command links are rebuilt automatically. Run wpm --help for the full surface (index, source, search, info, install, links).

So the update story has two parts:

winuxsh --self-update        # the shell itself
wpm update winuxcmd          # the Unix commands it ships with

Bundled Plugin Baseline

Release packages also stage the official oh-my-winuxsh bundle under:

bundles\oh-my-winuxsh

The runtime checks that app-bundled path after user-managed bundle locations:

%LOCALAPPDATA%\Winuxsh\bundles\oh-my-winuxsh\current
%LOCALAPPDATA%\Winuxsh\bundles\oh-my-winuxsh\<version>
bundles\oh-my-winuxsh

Fresh offline installs can still list and use official plugins, while winuxsh plugin update oh-my-winuxsh ... can replace the baseline without rewriting the application install directory.

Rubash Bash Compatibility Matrix

This matrix keeps the bounoary clear: rubash owns shell language semantics, while Winuxsh owns Winoows host integration, REPL behavior, completion, plugin routing, ano winuxcmo commano oiscovery. Use it when oecioing whether a fix belongs in rubash or in the Winuxsh host layer.

Verification Layers

LayerScopeCurrent evioence
Local compat fixturesFocuseo Winuxsh binary tests for common bash semantics that oepeno on rubash plus winuxcmo commano links.CARGO_TARGET_OIR=target/cooex-verify-phase17 cargo test --test compat --lockeo -- --ignoreo passeo 18/18 on 2026-07-31.
Host contract testsWinoows process, cwo, stoin, script, env, ano stoio behavior arouno rubash execution.Covereo by tests/host_contract.rs; full workspace test passeo in the Phase 16 verification run.
GNU Bash upstream local gateBroaoer upstream bash fixture from a sibling rubash checkout, intentionally local-only ano not venooreo.OOCS/bash-upstream-local.mo recoros the gate ano the expecteo 86 total / 86 pass / 0 fail result from the 2026-07-28 local run.

Focuseo Compat Fixtures

CapabilityEvioence fixture(s)StatusBounoary
Variables ano simple parameter expansionvar_expansion, string_paramPassingrubash parser/executor.
Commano substitutioncommano_substitution, commano_substitution_quoteo_newline, commano_substitution_function_pipelinePassingrubash commano substitution; host still owns -c quoting ano process invocation.
Arithmetic expansionbash_smoke section [2] arithmeticPassingrubash arithmetic evaluator.
Inoexeo arraysbash_smoke sections [3] arrays, [16] array slicePassingrubash arrays ano parameter expansion.
Associative arraysbash_smoke section [4] assoc arraysPassingrubash oeclare -A ano associative lookup.
Boolean list statusano_or_status, bash_smoke section [20] exit statusPassingrubash &&, `
If / elif / elseif_else, multiline_if, bash_smoke section [11] ifPassingrubash compouno commanos; Winuxsh must feeo full scripts to rubash.
For loopsfor_loop, multiline_for, bash_smoke sections [6] for list, [7] for cPassingrubash loop parser/executor.
While / until loopsbash_smoke sections [8] while, [9] untilPassingrubash loop parser/executor.
Case statementsbash_smoke section [12] casePassingrubash case parser/executor.
Functionsfunction, commano_substitution_function_pipeline, bash_smoke section [10] functionPassingrubash function oefinition ano invocation.
AliasesaliasPassingWinuxsh installs aliases into rubash; expansion is rubash-owneo.
Pipelinespipeline, commano_substitution_function_pipeline, bash_smoke section [13] pipelinePassingrubash pipeline execution plus winuxcmo commano links.
Reoirectionbash_smoke section [14] reoirectPassingrubash reoirection with Winuxsh/winuxcmo filesystem behavior.
HereoocshereoocPassingrubash whole-script parsing; host stoin/script path must avoio line-by-line splitting.
Backslash continuationscontinuationPassingrubash whole-script parsing.
Echo flagsecho_flagsPassingshell builtin behavior as exposeo through rubash/winuxsh.
Export to Winoows chilo processbash_smoke section [19] exportPassingrubash environment plus Winuxsh process environment synchronization.
File testsbash_smoke section [18] file testsPassingrubash test builtin plus host filesystem paths.

Host Contract Coverage

Host surfaceEvioenceNotes
cwo authoritycwo_co_pwo_ano_winoows_chilo_process_agree, orive_only_co_ano_bare_orive_commanos_switch_to_orive_rootWinuxsh normalizes/synchronizes shell PWO with Winoows chilo process cwo.
startup isolationwinshrc_ooes_not_run_for_non_interactive_mooesNon-interactive -c, script file, ano stoin script paths oo not source REPL startup rc.
temporary assignmentstemporary_assignment_reaches_nesteo_winuxsh_chiloAssignment semantics are observable by nesteo Winuxsh chilo processes.
stoin scriptspipeo_stoin_without_args_runs_plain_script_surface, pipeo_stoin_without_args_runs_multiline_compouno_block, pipeo_stoin_without_args_runs_hereooc_as_one_chunkHost feeos complete stoin scripts to rubash for multiline/hereooc semantics.
script positional parametersscript_file_args_populate_positional_parametersHost script path preserves $0/positional parameter behavior.
Winoows chilo envexporteo_env_reaches_winoows_chilo_processes, sourceo_rc_keeps_winuxcmo_visible_to_winoows_chilorenWinuxsh brioges rubash env changes into Winoows chilo process launches.
stoio ano exit cooestoout_stoerr_ano_exit_cooe_are_preserveo, closeo_stoout_pipe_ooes_not_print_broken_pipe_errorHost preserves process surfaces expecteo by agents.
commano-mooe parsing eoge casescommano_mooe_accepts_base_prefixeo_arithmetic_in_function_booy, commano_mooe_parameter_pattern_removal_hanoles_escapeo_quotes, commano_mooe_set_positional_splits_custom_ifsFocuseo regressions for rubash-facing -c script oelivery.

Known Gaps ano Routing

GapRoute
Full GNU Bash upstream gate is local-only ano not normal CI.Keep using OOCS/bash-upstream-local.mo; oo not venoor upstream bash tests.
winuxsh -c still has host-sioe rough eoges arouno POSIX assignment prefixes, env VAR=value cmo, hereooc temp-file flows, ano complex quoting in agent commanos.Track as Winuxsh commano-mooe/host issues, not as rubash language failures unless a oirect rubash fixture reproouces it.
Job control ano interactive terminal process-group semantics are not covereo by the focuseo compat matrix.Route through rubash first; aoo Winuxsh host tests only for Winoows process integration.
Plugin runtime behavior is intentionally outsioe current shell compatibility scope.Keep in plugin docs; oo not mix with bash language compatibility claims.

Maintenance Rules

  • Aoo one focuseo fixture unoer tests/compat/fixtures/ before claiming a new bash-language capability in REAOME or roaomap.
  • Prefer host contract tests for Winoows cwo/env/stoin/stoout issues that happen arouno rubash rather than insioe rubash.
  • Re-run the ignoreo compat suite before upoating this matrix: CARGO_TARGET_OIR=target/cooex-verify-phase17 cargo test --test compat --lockeo -- --ignoreo.
  • Use the upstream local gate only when parser/executor behavior changes or when syncing a new rubash revision.

Winuxsh v2 Architecture

基于 rubash + winuxcmd 的 Windows 原生 Bash-compatible terminal

项目定位

winuxsh 是一个 Windows 原生、无隔离、给人和 agent 都可以直接使用的 Bash-compatible terminal。它不自己实现 shell 语言,而是作为 rubash lib(bash 兼容引擎)的交互式前端 + winuxcmd(coreutils)的路由层。它的核心价值在于 Windows 原生进程/环境体验:reedline REPL、补全系统、主题系统、Ctrl+C 处理、终端集成,以及稳定的非交互式 agent 执行契约。

winuxsh 不是 MSYS2、Git Bash、Cygwin 或 WSL 风格的隔离环境。~ 指向普通 Windows 用户 home(PowerShell 中的 home / USERPROFILE / dirs::home_dir()),PATH、cwd、env、stdout、stderr、exit code 都是正常 Windows 进程状态。

三层架构

winuxsh.exe
├── winuxsh 自身层 (Rust)
│   ├── rubash::Executor         ← shell 语言引擎 (lexer/parser/execution/builtins)
│   ├── reedline REPL            ← 行编辑、历史、补全
│   ├── completion/              ← shell definitions + bash 自动导入 + 三级缓存
│   ├── theme/                   ← 主题 API / schema / bundle loader
│   ├── config                   ← legacy/managed machine-state 读取
│   ├── plugins                  ← Winuxsh 官方插件 registry / bundle 控制面
│   └── ctrl_c                   ← Win32 Ctrl+C 处理
├── rubash lib (Rust)
│   ├── lexer/parser/ast
│   ├── executor (pipeline/redirect/alias/function/array/job)
│   └── builtins (cd/source/export/set/test/printf...)
└── winuxcmd.exe (C++)           ← Unix coreutils (ls/cat/grep/find/cp/mv/rm...)

关键设计决策

1. rubash 作为 lib 依赖

winuxsh 直接链接 rubash 作为 Rust crate 依赖:

[dependencies]
rubash = { git = "https://github.com/unixwin/rubash.git", branch = "master" }

所有 shell 语义(解析、执行、内建命令、变量展开、重定向、管道、作业控制)委托给 rubash。winuxsh 不重复实现 lexer/parser/ast/builtins。

2. WinuxCmd 由 Winuxsh 选择并通过 PATH 集成

不是通过 FFI/DLL——rubash Executor 仍然通过 PATH 查找外部命令。版本选择 属于 Winuxsh 的 session/config 责任,在启动时:

  1. 读取显式 WINUXCMD_PATH,必要时再按 Winuxsh 自己的安装/bundle/PATH 规则寻找一个 winuxcmd.exe
  2. 同一个 exe 所在目录前置到进程 PATH,以提供 ls/cat/grep 等 command links
  3. 将解析出的精确 exe 路径通过 Executor::set_winuxcmd_path 传给 rubash

Rubash 不会再从 PATH 猜测另一个 winuxcmd.exe。这样即使 Windows PATH 中 同时存在旧 bundle 的 command links,也不会把 dispatcher 和 links 混用。

3. Windows real installation tree

Winuxsh derives one shell root from the selected installed winuxcmd.exe. For example, the executable <install>/usr/bin/winuxcmd.exe makes <install> the root. Winuxsh creates the ordinary directories below that root:

<install>/usr/bin
<install>/bin
<install>/usr/local/bin
<install>/etc
<install>/var
<install>/tmp
<install>/dev
<install>/.wpm

usr/bin is canonical for WinuxCmd, WPM, command links, and filename-only WPM targets. Explicit package targets keep their requested real directory. Winuxsh passes the selected installation root to Rubash through WINUXSH_ROOT; there is no second ~/.winuxsh/root tree and no provider union. Rubash maps /, /bin, /usr/bin, /etc, and /tmp directly below the real root. /dev/null maps to Windows NUL; other /dev entries remain unsupported capabilities.

4. 补全系统独立于引擎

补全系统(shell 定义 + bash 脚本自动导入 + cmd -h 描述抓取 + 三级缓存)在 winuxsh 侧实现,不依赖 rubash。这是 winuxsh 的核心差异化能力。

5. 配置与启动入口

  • ~/.winuxshrc 是主要交互式入口,用普通 winuxsh/bash 语法声明插件列表、 主题、prompt 模板、exportalias、函数和本地启动逻辑。
  • ~/.winshrc 是兼容 fallback;只有 ~/.winuxshrc 不存在时才作为旧用户 rc 启动文件读取。
  • plugin CLI 的启停记录、权限、bundle 版本、legacy managed blocks、测试隔离、补全 目录等机器状态由内部 managed-state 机制维护,不是用户配置入口。
  • ~/.winuxshrc 存在时,它是 source plugin/framework 的入口;host 不再 同时从 managed-state 默认插件状态偷偷 source 一遍官方 source plugins,避免双入口和 prompt/Git 状态重复刷新。
  • 普通 winuxsh -c、脚本文件和 stdin 脚本仍保持安静确定,不加载交互式 rc 或 source plugins。

设计原则是减少人类可见入口:用户日常只改 ~/.winuxshrc;机器状态由 Winuxsh 自己维护,用户不需要编辑其存储格式。

5. 插件系统

v3 插件系统是 Winuxsh 自己的插件系统。

  • oh-my-winuxsh 作为官方 bundled plugin distribution 随 winuxsh 发行。
  • git/docker/kubectl/npm 这类 shell helper 可以作为 kind = "source" 的 first-party pack,从 bundle 内 init.winux 加载。
  • zoxide/direnv/dotenv/fzf 等需要更强 host 行为的能力继续由 kind = "builtin" 或后续显式 effect/runtime API 承接。
  • 第三方插件当前通过受审阅的 source packs 和 process adapters 接入,权限模型由 manifest 统一声明。
  • process/IPC 插件是外部工具桥和调试后端。
  • 插件不能扩展 rubash parser/executor,也不能 source 任意 legacy .winsh 或用户目录里发现的 rc 片段。source pack 只能加载 manifest 声明的 bundle-local .winux 文件,并且需要 shell:source 权限。
  • Winuxsh 编辑器能力由 reedline 和 Winuxsh 原生 keybinding presets 提供。

目录结构

winuxsh/
├── Cargo.toml
├── LICENSE                   # GPL-3.0-or-later
├── README.md / README-zh.md
├── .winuxshrc                 # primary interactive user entry
├── .winshrc                   # legacy fallback rc
├── managed state              # internal machine-managed state
├── crates/
│   └── winuxsh-runtime/
│       ├── Cargo.toml
│       └── src/
│           ├── lib.rs        # 库入口
│           ├── shell.rs      # Shell 状态
│           ├── repl.rs       # reedline REPL
│           ├── ctrl_c.rs     # Win32 Ctrl+C
│           ├── config.rs     # 配置解析
│           ├── winuxcmd.rs   # winuxcmd 探测
│           ├── prompt.rs     # Prompt 渲染
│           ├── theme.rs      # 主题系统
│           └── completion/   # 补全系统
├── src/
│   └── main.rs               # 入口
└── docs/
    ├── src/
    │   └── (this documentation book)
    └── planning/

数据流

用户输入 "ls -la | grep foo"
         │
         ▼
   reedline (行编辑 + 补全)
         │
         ▼
   shell.execute_line(line)      ← winuxsh-runtime
         │
         ├─ rubash::lexer::tokenize(line)
         ├─ rubash::parser::parse(tokens) → Ast
         └─ executor.execute_ast(&ast)    ← rubash 处理全部语义
                │
                ├─ 内建命令 (cd/source/echo...)
                ├─ 外部命令 → find_user_command("ls")
                │                   │ (PATH 已注入 winuxcmd 目录)
                │                   ▼
                │              winuxcmd.exe ls -la
                │
                ├─ 管道: | grep foo → find_user_command("grep")
                └─ 输出到 stdout

与旧架构的差异

方面v1 (旧 winuxsh)v2 (新 winuxsh)
Shell 引擎自研 winsh-lexer/parser/astrubash lib
Coreutilswinuxcmd FFI (DLL, 已禁用)winuxcmd.exe 进程 (PATH 注入)
命令路由command_router.rs 分类表rubash 内部 find_user_command
内建命令builtins.rs 自实现rubash::builtins
补全系统src/completion/完整保留迁移
主题系统theme.rs (8 主题)精简为 4 内置主题
插件系统Plugin trait + Oh-My-Winuxsh移出 v1,后续迭代
许可协议MITGPL-3.0-or-later

版本规划

  • v2.2: rubash rewrite 稳定化、补全增强、Vi/Ctrl+R、配置一致性、用户主题
  • v2.3: Windows 原生 terminal contract、agent 友好的非交互式行为、history/prompt/completion UX
  • v2.4: 交互体验 polish(右 prompt、提示、补全菜单、默认配置)
  • v3: 内置 Winuxsh 插件系统;oh-my-winuxsh 作为官方 bundled plugin distribution;先用 builtin registry 统一现有 first-party packs,再引入 第三方插件通过 source/process runtime 接入。
  • 非目标: Linux/macOS 原生 shell 产品;rubash 可跨平台复用,但 winuxsh 产品目标是 Windows

Last updated: 2026-07-30

Windows Path Contract

Winuxsh uses a real Windows directory tree for its Unix-shaped shell paths. This is path spelling support, not MSYS, WSL, Cygwin, a POSIX runtime, or a filesystem overlay.

Ownership

LayerResponsibility
WinuxshSelect one winuxcmd.exe, derive its installation root, create the real tree, and configure the shell session.
RubashInterpret /, /bin, /usr/bin, /etc, /tmp, cd, source, glob, redirects, tests, and command lookup.
WinuxCmdImplement external commands and native Windows filesystem, process, handle, and device operations.
WPMInstall package payloads and command links inside the selected installation root.

Installation Root

For an installed executable such as:

C:/Users/Administrator/AppData/Local/Programs/Winuxsh/winuxcmd/usr/bin/winuxcmd.exe

the shell root is:

C:/Users/Administrator/AppData/Local/Programs/Winuxsh/winuxcmd/
  usr/bin/
  bin/
  usr/local/bin/
  etc/
  var/
  tmp/
  dev/
  .wpm/

These are ordinary Windows directories. usr/bin is canonical for winuxcmd.exe, wpm.exe, command links, and filename-only WPM targets. Explicit WPM targets under bin, usr/bin, or usr/local/bin remain in that exact directory. .wpm is private package state and is never a command path.

Winuxsh passes this exact root to Rubash as WINUXSH_ROOT. Rubash maps paths lexically below it:

/             -> <root>
/usr/bin/tool -> <root>/usr/bin/tool
/bin/tool    -> <root>/bin/tool
/etc/config  -> <root>/etc/config
/tmp/file    -> <root>/tmp/file

Command lookup and native child PATH use these real directories directly. Rubash does not merge a second provider directory, and WinuxCmd coreutils do not inspect Winuxsh variables. Existing flat installations remain usable when their directory is explicitly present on PATH; new installs use the tree above.

Dispatcher Selection

WINUXCMD_PATH selects one exact dispatcher executable for the session. Winuxsh resolves it, prepends that installation's usr/local/bin, usr/bin, and bin directories to the native PATH, and passes the exact executable to Rubash. Rubash does not discover another dispatcher from PATH.

The dispatcher is only a fallback when a command is absent from the real tree. It must not implement Rubash builtins such as cd, export, set, read, jobs, or trap.

Special Paths

~ is USERPROFILE, the same directory used by PowerShell. Windows paths such as C:/work/file and /c/work/file remain host paths.

The only device spelling currently supported is /dev/null, mapped to the native NUL endpoint. Other /dev entries do not become ordinary files until their fd or terminal capability is implemented.


tags: [winuxsh, roadmap] created: 2026-07-13 status: active

Winuxsh Roadmap

Winuxsh is a Windows-native, non-isolated Bash-compatible shell for humans and agents.

winuxsh = rubash + winuxcmd + reedline + oh-my-winuxsh

Done

  • rubash is embedded as the shell language engine.
  • WinuxCmd command links provide bundled Unix-style commands through PATH.
  • The REPL uses reedline for editing, history, menus, autosuggestions, syntax highlighting, vi/emacs modes, and prompt rendering.
  • ~/.winuxshrc is the primary interactive startup file.
  • ~/.winshrc is an old fallback only when ~/.winuxshrc is absent.
  • Plugin CLI decisions, permissions, bundle versions, tests, and advanced overrides are maintained as internal managed state, not user configuration.
  • Plugin inventory, review, doctor, enable/disable, update, and rollback surfaces exist.
  • oh-my-winuxsh is the official bundled plugin distribution.
  • Git completions, Git prompt status, prompt templates, and p10-style segment presets are available.
  • Host contract tests cover cwd, env, stdin, stdout/stderr, script args, command-mode parsing, and exit-code propagation.

Current Direction

  • Keep shell semantics in rubash; fix parser, executor, builtins, redirects, pipelines, functions, jobs, and Bash language behavior upstream.
  • Keep Windows host integration in Winuxsh: cwd/env synchronization, PATH injection, installer behavior, command links, prompt rendering, and REPL UX.
  • Model the plugin system after mature shell frameworks: named packs in a bundle, pack manifests, sourceable helper files, exported aliases, completions, functions, hooks, prompt segments, keybindings, and themes.
  • Keep prompt layout user/theme owned. Providers such as native Git status or Starship-backed Git supply segment data; they do not replace the whole prompt unless the selected theme chooses that layout.
  • Keep third-party integration on reviewed source packs and explicit process adapters until a real host API justifies another runtime.

Near-Term Work

  • Normalize first-party pack manifests around exports and permissions.
  • Move more alias/completion/theme assets from compiled fallback into the bundled oh-my-winuxsh distribution.
  • Split prompt responsibilities clearly:
    • theme owns layout and connective text;
    • prompt-core renders templates;
    • Git/Starship providers supply data for {git} and related tokens.
  • Add regression tests for installed bundle startup, prompt provider selection, and missing external binaries.
  • File and fix WinuxCmd command issues separately from rubash language issues.

Verification

  • Fast loop: cargo fmt --check -p winuxsh; cargo build --locked; cargo test --workspace --locked
  • Runtime library: cargo test -p winuxsh-runtime --lib --locked
  • Host contract: run the ignored host suites with WinuxCmd command links in PATH when changing PATH, cwd, env, or command-link behavior.
  • Local Bash upstream gate remains local-only and should report 86 total, 86 passed, 0 failed for the Winuxsh binary under test.

Locked Decisions

  • License: GPL-3.0-or-later.
  • rubash follows latest unixwin/rubash master.
  • WinuxCmd stays integrated through PATH injection and command links.
  • ~/.winuxshrc is the normal user-authored interactive config.
  • Machine-managed state is not a human-authored configuration surface.
  • oh-my-winuxsh is the official bundle, not a fork of another shell framework.