Skip to content

Cross-Platform Shell Support

Kangentic spawns agent CLI processes in platform-native shells. This page documents how shells are detected, adapted, and configured across platforms.

Kangentic auto-detects the user’s shell in the following order:

PlatformDetection Order
WindowsPowerShell 7 (pwsh) > PowerShell 5 (powershell) > Git Bash (bash) > cmd.exe
macOSzsh > bash > fish > nushell (nu) > sh (default: $SHELL or zsh)
Linuxbash > zsh > fish > dash > nushell (nu) > ksh > sh (default: $SHELL or bash)

Override the detected shell in Settings under the Terminal tab, or set terminal.shell in the config file.

Kangentic adapts command execution for each shell:

ShellAdaptation
PowerShellLaunched with -NoLogo (no & prefix). On Windows, a Set-Location -LiteralPath prelude corrects the working directory when the path contains [ or ], which PowerShell would otherwise treat as wildcards
WSL BashSpawned as wsl.exe plus its distro arguments. The agent command’s leading executable path is converted to /mnt/c/... format. Invoked with the arguments already written into the shell string, so no --login is added
cmd.exeNo --login flag (it has no such concept)
fishNo --login flag (fish doesn’t support it)
nushell (nu)No --login flag
bash/zsh/dash/ksh/shStandard --login invocation. --login is the fallback, applied to every shell that is not WSL, cmd.exe, PowerShell, fish, or nushell

An agent spawn prefixes the command it types with the shell’s own clear: Clear-Host; for the PowerShell family, cls & for cmd.exe, and clear; for everything else (bash, zsh, fish, nu, dash, ksh, sh, WSL, Git Bash). The shell then erases its own startup preamble and the command echo the instant the command runs, so what the terminal, the scrollback ring, the headless parser, replays, and the paired phone all receive is a real clear in the real byte stream rather than a heuristic guess about which startup bytes to strip. That matters because those bytes move: pwsh 7.6 started emitting cursor-hide and erase sequences inside its escape-only startup preamble, which broke every detector keyed on them.

Command Terminals are deliberately exempt. They are your own shell, with no spawn echo to strip and no reason to wipe what you already typed.

Cross-platform path handling uses two key utilities:

Converts Windows backslashes to forward slashes for consistent path handling across platforms. Used when passing paths to shells and CLI tools.

Properly escapes and quotes arguments for the target shell: single quotes for unix-like shells (bash, zsh, WSL), double quotes for PowerShell and cmd.exe. The target shell is passed explicitly at every spawn call site, so quoting always matches the shell the command is about to run in.

Rewrites the leading executable path of a command into POSIX form for unix-like shells. It recognizes all three quote forms a command builder can emit - a bare path, a double-quoted path, and the single-quoted path quoteArg produces for unix-like shells - plus UNC paths (\\server\share\...). A single-quoted token stays single-quoted so shell-active characters in a legal Windows path remain inert. Before this handled the single-quoted case, selecting Git Bash or WSL as the terminal shell broke every agent spawn with “command not found”.

When running under Git Bash on Windows, paths like /c/Users/... are used instead of C:\Users\.... Kangentic detects Git Bash and adjusts path formatting accordingly.

For WSL shells, Windows paths are converted using the /mnt/ prefix:

  • C:\Users\project > /mnt/c/Users/project

Kangentic detects WSL shells and applies special handling:

  • Detection: wsl --list --quiet, with a 5-second timeout
  • Docker filtering: WSL Docker Desktop distributions (distros whose name starts with docker-) are filtered out of the shell list
  • Spawn: the stored shell spec (wsl -d Ubuntu) is split into an executable and its arguments, and the executable is spawned as wsl.exe. The extension is deliberate: node-pty’s ConPTY executable search cannot resolve the bare name wsl, and a session spawned that way exits immediately with no output
  • Path conversion: the agent command’s leading executable path is converted to /mnt/c/.... The command itself is written into the PTY after the shell starts, never passed in argv

Converting the CLI path to /mnt/c/... launches the Windows agent binary through WSL’s interop layer, which can only execute PE .exe files. Two consequences follow, both documented limitations rather than bugs:

  • npm-installed .cmd / .bat shims cannot be launched from inside WSL. Git Bash can run them; WSL interop cannot. On WSL you need the agent’s native .exe install.
  • A CLI installed inside the distro is not discovered. Detection resolves on the Windows host, identically for every shell. Preferring a distro-native binary would also mean converting every path argument the spawn passes (--settings, --mcp-config are Windows paths, correct for a Windows binary and wrong for a Linux one), so it is a possible future feature, not current behavior.

When spawning an agent, Kangentic strips the parent Claude Code session’s markers from the child environment: CLAUDECODE and every CLAUDE_CODE_* variable (entrypoint, session ID, execpath, and the nested-session flag). This keeps a Kangentic-spawned agent a clean top-level session. Without it, a nested Claude Code child would refuse to start or inherit the parent’s session identity and lose its own transcript on resume. The stripping is harmless for non-Claude agents, which ignore these variables, and ANTHROPIC_* keys (BYOK / API auth) are left untouched.

Two CLAUDE_CODE_* keys survive the strip, both renderer tuning flags rather than session-identity markers:

KeyBehavior
CLAUDE_CODE_ALT_SCREEN_FULL_REPAINTKept, and on Windows defaulted to 1 when you have not set it yourself, working around an upstream alternate-screen repaint defect. Set it yourself to override that default
CLAUDE_CODE_SCROLL_SPEEDKept so your own exported value reaches the agent, but deliberately never defaulted. A default of 3 was shipped and reverted the same day: wheel reports coalesce into single large jumps, and a 3x multiplier pushed those past the threshold where the fullscreen TUI’s differential renderer mis-assembles frames. The CLI’s own default of 1 matches the native terminals verified clean

Two more adjustments happen at the same chokepoint, both so agent TUIs render in color:

  • TERM is defaulted to xterm-256color when the merged environment has none, treating an empty string as absent the way capability detectors do. This only ever fills a gap: an inherited or caller-supplied TERM passes through untouched. It matters on Windows specifically, because node-pty turns its spawn name option into the child’s TERM only on POSIX, so a PowerShell-launched Kangentic previously gave its children no TERM at all and CLIs that key color off it (Antigravity’s agy is the clear case) rendered monochrome.
  • NO_COLOR is stripped, but only when the merged environment also carries CLAUDECODE. Claude Code exports NO_COLOR=1 into its tool shells, so a Kangentic launched from inside a Claude Code session was force-dimming every color-capable CLI in every agent terminal. A NO_COLOR without that parentage marker is a deliberate preference and survives, as does one set per spawn by a caller.

On Windows, Kangentic sets the Application User Model ID (AUMID) for proper taskbar grouping and notification association:

ContextAUMID
Developmentcom.kangentic.dev
Productioncom.kangentic.app

This ensures development and production instances have separate taskbar entries and notification channels.

On macOS, the custom title bar positions the traffic light buttons (close, minimize, maximize) with specific offsets to align with the app’s header layout. The position is defined in the main process window configuration.

See also:

Kangentic is free and open source. A star helps other people find it.

Star on GitHub