← Agent directory / Universal guide

Wire any agent onto niubash

Universal guide Works for any agent Source of truth: agents.md

How an agent picks its shell follows patterns — work out its detection mechanism and you can wire it. Your agent never runs commands inside "the shell you are using": it picks its own, and on Windows that pick is decided by exactly four detection mechanisms. This page takes them apart one by one, then gives a three-step decision flow that works for agents the catalogue has never listed.

The four detection mechanisms

From agents.md, "The four mechanisms". The first three are wireable by you; the fourth is the hard limit behind every bare-name invocation — and the reason the other three exist. Each row's "how to wire it" lands on the matching copy block in the step-3 flow.

MechanismCoverageHow to wire it
① $SHELL · POSIX convention Agents that read the process environment — the largest class, including all POSIX-style CLIs (opencode is the pure specimen: zero occurrences of niu in the binary, no shell setting; $SHELL is the whole mechanism). Works automatically inside a niu session: niu exports SHELL=<path to niu.exe>. But $SHELL is not persisted — the same agent launched from the Start menu / Explorer sees an empty value. Launch the agent inside niu (step 3 · try step 1 first), or persist SHELL into the user environment (block a).
② per-agent explicit configuration Agents exposing a shell settings field / CLI flag: Zed (terminal.shell.program), Claude Code (CLAUDE_CODE_GIT_BASH_PATH), the VS Code family (automationProfile), DSH (profile plugin). Config-reading mechanisms are launch-method independent — set once, effective forever. Find its shell setting via the section-4 self-check, then point it at niu.exe or the installer-placed bash.exe (block b is the universal VS Code family snippet).
③ Git for Windows probe Agents with hard-coded Git paths, or that infer from git on PATH: Claude Code (scans C:\Program Files\Git and the x86 directory first, then infers from git), the whole VS Code family (Copilot / Windsurf / Trae / ZCode + the Cline, Roo Code, Kilo Code, Continue extensions). It probes fixed locations: C:\Program Files\Git\bin\bash.exe and friends. The niubash installer already places a bash.exe placeholder on those paths (x86 candidates and sh.exe included); run once as administrator (block c verifies).
④ Bare-name resolution Callers that throw the bare name bash / sh to PATH / ComSpec / PATHEXT. The hard limit: in CreateProcess's search order the system directory (System32) comes before PATH — a bare bash always hits C:\Windows\System32\bash.exe (WSL) first. See agents.md, "Why PATH cannot win against System32". A user PATH cannot outrank System32: either give a full path that lands on the Git probe (fold into ③), or make the caller use sh (no System32 namesake exists).

The wiring decision flow (three steps)

Step 1 · Always try "launch from a niu session" first

This is the only approach that "just works" most of the time: niu exports SHELL=<path to niu.exe>, and any agent honoring the POSIX convention picks it up as-is. That is how the agents.md author runs: process tree powershell.exe ← niu.exe ← opencode.exe, while opencode's shell selector is literally process.env.SHELL ?? which("bash") ?? "/bin/sh". Zero cost — try it first.

Launch inside a niu session + verify
# 1) Enter a niu session ($SHELL is exported here, pointing at niu.exe)
niu

# 2) Start your agent from inside the niu session (example):
opencode          # or codex / any CLI agent

# 3) Have the agent run the verify command below, then match the output
#    against step 2's signature table:
#    echo "SHELL=$SHELL"; uname -s; uname -a
The verify command to have the agent run: echo "SHELL=$SHELL"; uname -s; uname -a

But $SHELL is not persisted: it exists only in descendant processes of the niu session. The same agent launched from the Start menu / Explorer sees an empty $SHELL and falls back to which("bash") — which on a WSL-installed machine resolves to C:\Windows\System32\bash.exe, and suddenly commands run inside Linux. The next two steps pin the result down.

Step 2 · Match the output against the signature table

Compare the three lines the agent produced with the table:

You seeActual shellNext move
uname -s = MSYS_NT-…, and uname -a ends with x86_64 Msys niu (winuxcmd shim) Success $SHELL points at niu.exe; add block a to pin it across launch methods.
uname -s = MINGW64_NT-…, MSYSTEM=MINGW64 Git Bash (Git for Windows' own runtime) A probe-type mechanism won the race: go mechanism ③ (once the placeholders are in place, the probe hits niubash's bash.exe) or mechanism ② (explicit); persisting $SHELL also works as a floor.
uname -s = Linux WSL — the agent fell back to which("bash") and hit System32\bash.exe The deepest silent wrong-shell hit: go mechanism ② or mechanism ③, and use mechanism ① (block a) to prevent the fallback.
uname missing, $SHELL empty PowerShell or cmd (tell them apart via $PSVersionTable.PSVersion vs %COMSPEC%) Safe but not bash-compatible: go mechanism ② (for the VS Code family that is block b).

The same signature check shows up in Cursor's own support thread: fixed means uname -a ends with MINGW64_NT-… instead of microsoft-standard-WSL2 — the niu target is MSYS_NT-… (ending x86_64 Msys).

Step 3 · Configure per mechanism (three copy blocks)

Block a · persist $SHELL (mechanism ① · PowerShell · user-level · no admin)
# Persist SHELL into the user environment (same trick as the installer:
# one registry value, no elevation required)
# Adjust the path to your actual install location; default is %LOCALAPPDATA%\Programs\Niubash
[Environment]::SetEnvironmentVariable('SHELL', "$env:LOCALAPPDATA\Programs\Niubash\niu.exe", 'User')

# Undo (matches the installer's uninstall semantics):
# [Environment]::SetEnvironmentVariable('SHELL', $null, 'User')

# Note: only affects processes started afterwards — reopen your terminal / agent

The installer itself writes SHELL into the user environment too (removed on uninstall) — item 1 of agents.md's "Recommended order of work": one registry value, no elevation, covering the largest agent class (all POSIX-style CLIs) and making $SHELL independent of the launch method. The command above is its manual twin.

Block b · settings.json automationProfile (mechanism ② · universal for the VS Code family)
// VS Code family settings.json (VS Code / Windsurf / Trae / ZCode, plus the
// extensions that run commands through the editor terminal or an automation
// profile: Cline, Roo Code, Kilo Code, Continue, ...)
// Swap path for your actual install; default %LOCALAPPDATA%\Programs\Niubash\niu.exe:
"terminal.integrated.automationProfile.windows": {
  "path": "C:\\Users\\<your-user-name>\\AppData\\Local\\Programs\\Niubash\\niu.exe",
  "args": []
}

Agents that shell out through an automation profile inherit this setting (the VS Code family's explicit-control method). Beyond the placeholder paths, pointing the profile straight at niu.exe skips one hop of the bash.exe launcher.

The Cursor exception: Cursor's IDE agent ignores terminal.integrated.defaultProfile.windows and automationProfile.windows and still runs PowerShell (workaround: enable the Legacy Terminal Tool setting); its Agent CLI is hard-coded to PowerShell. See the Cursor detail page.

Block c · verify the installer's Git probe placeholders (mechanism ③)
# The installer's optional elevated step (run once as administrator) places the
# placeholders mechanism 3 needs:
#   C:\Program Files\Git\bin\bash.exe         <- Claude Code / VS Code family hard-coded probe 1
#   C:\Program Files (x86)\Git\bin\bash.exe   <- second candidate path
#   C:\Program Files\Git\bin\sh.exe           <- for tools that want sh next to bash
# Verify the placeholders (first line should print True; second should print MSYS_NT-...):
Test-Path 'C:\Program Files\Git\bin\bash.exe'
& 'C:\Program Files\Git\bin\bash.exe' -c 'uname -s'

These files are placed by the installer's optional elevated step — run once as administrator (Program Files is not writable from a user PATH). One cost, the whole family benefits: Claude Code's and the VS Code family's hard-coded probes all land on niubash's launcher from then on. That bash.exe is not niu itself but a launcher that starts niu.exe as a child (agent → bash.exe → niu.exe): about 17.6 ms extra per -c call (niubash#377); the historical "one console window flash per command" problem (niubash#379) was fixed in rubash#668 — verify the flashes are gone once you upgrade.

Agent not in the catalogue? Ask three questions

The verified list is short; the agent ecosystem is not. Most agents hide their shell detection in one of three places — ask, in order:

Figured it out? PRs welcome — add your findings to the /en/agents/ catalogue (agent name, mechanism class, configuration method, verify output): github.com/unixwin/unixwin.dev ↗. The "not verified here" list in agents.md is still long — Amazon Q Developer CLI, Goose, Amp, OpenHands, Devin… every bit of reconnaissance is a contribution.

Two things not to do while wiring (agents.md, "Two things not to do"): first, never add winuxcmd\usr\bin to PATH — hundreds of names, many colliding with System32; second, never try to replace C:\Windows\System32\bash.exe.

Known traps · four of them

Sources