#1180·zoxide

winget packaging as portable prevents ssh usage

Author: meopCreated Feb 13, 2026Updated May 10, 2026

Observed Issue

Winget is packaging zoxide as a portable app.

This means that Winget puts a symlink here: ~/AppData\Local\Microsoft\WinGet\Links\zoxide.exe

The target is actually here: ~/AppData\Local\Microsoft\WinGet\Packages\ajeetdsouza.zoxide_Microsoft.Winget.Source_8wekyb3d8bbwe\zoxide.exe

This is fine for locally running zoxide, via Powershell or Nushell.

But when remoting to a Windows machine and targeting either Powershell or Nushell, neither will launch zoxide. The error given is variations of "I/O error ╰─▶ × Could not spawn foreground child: The path cannot be traversed because it contains an untrusted mount point. (os error 448)"

Possible Workaround

I tried to just enable remote symlink evaluation, but it did not help: fsutil behavior set SymlinkEvaluation R2L:1 R2R:1 Not sure if it needs a restart, or if it is just not the reason for the error. It would also not be ideal to globally enable something like this anyway.

Powershell is able to bypass the symlink:

function Get-RealPath($n) {
  (Get-Command $n -Type Application | Select-Object -First 1).Path |
    Get-Item |
    ForEach-Object { $_.Target ?? $_.FullName }
}

function Initialize-Tool($n) {
  Invoke-Expression "function global:$n { & '$((Get-RealPath $n))' @args }"
  & $n init powershell | Out-String | Invoke-Expression
}

Initialize-Tool zoxide

Nushell is not able to, via its built-ins.. but it can wrap Powershell or Cmd, which can:

## cmd, works over ssh
# def get-realpath [n] {
#   let p = (which $n | get 0?.path?)
#   if ($p | is-empty) { return $n }
#   let target = (
#     ^cmd /c dir /a $p |
#       decode utf-8 |
#       str replace --all --regex '\x1b\[[0-9;]*[mK]' '' |
#       lines |
#       find "[" |
#       first 1 |
#       parse -r '.*\[(?P<t>.*)\]' |
#       get 0?.t?
#   )
#   if ($target | is-empty) {
#     $p
#   } else {
#     $target | str replace --all --regex '^[0-9;]*m' ''
#   }
# }

## pwsh, works over ssh
def get-realpath [n] {
  let ps_cmd = ([
    '(Get-Command ', $n, ' -Type Application | Select-Object -First 1).Path | ',
    'Get-Item | ForEach-Object { $_.Target ?? $_.FullName }'
  ] | str join "")
  pwsh -NoProfile -Command $ps_cmd | str trim
}

## nushell, does not work over ssh
#def get-realpath [n] {
#  which $n | get 0?.path? | path expand
#}

Then for Nushell, I can mutate what zoxide init produces, force it to bypass the symlink:

def initialize-tool [n init_args] {
  let p = (get-realpath $n)
  $"def --env ($n) [...args] { ^'($p)' ...$args }\n(
    ^$p ...$init_args | str replace --all --regex $"\\^($n)\\b" $"^'($p)'"
  )" | save -f ([$NU_VENDOR_DATA_DIR, $"($n).nu"] | path join)
}

## preserves external cmd calls, does not work over ssh
# def initialize-tool [n init_args] {
#   ^$n ...$init_args | save -f ([$NU_VENDOR_DATA_DIR, $"($n).nu"] | path join)
# }

initialize-tool zoxide [init nushell]

But I do not really want Nushell dependent on Powershell or Cmd, just to bypass a symlink

Proposed Solution

I am not sure if there are benefits to Winget packaging zoxide as a portable app, other than a simpler installer

I would like to propose that we produce a non-portable installer for Winget to use for zoxide, so that it installs to a real path somewhere, no symlink

This would put it more in line with how starship is packaged

Then I would not have to do any workarounds as above, which are complex and slow

I can help to create a pull request for this if it would be approved

Thank you