Skip to content

Windows and WSL

Run qialike on Windows natively or under WSL2, and avoid the path, line-ending and sandbox pitfalls.

qialike runs on Windows natively, and also works under WSL2 — either is fine, and WSL2 is an option rather than a requirement. Native Windows gets the harness’s ACL restricted-token runner for OS-level process isolation (the peer of Linux’s bubblewrap/Landlock and macOS’s Seatbelt); WSL2 gets the Linux rungs. This page covers WSL2 first, then the native differences.

Choose your setup

SetupKernel-level sandboxNotes
Native WindowsYes — the ACL restricted-token runner, out of the boxNo WSL needed; qialike.exe is a native program. The pure-JS fs-sandbox fence and the workspace-write + ask approval boundary apply on top.
WSL2 (optional)Yes — bubblewrap, falling back to Landlock (kernel ≥5.13 with the LSM enabled)A real Linux environment; the single-file Linux binary runs unchanged.

The permission (presets) row is enabled on every platform, Windows included. The runner has to be carried into the single-file build: the native koffi it depends on is stubbed (apps/tui-bin/stub/koffi.js), and the runner process itself is embedded and launched by the binary (apps/tui-bin/src/windows-acl-shim.ts), because the harness locates it by module specifier and a compiled binary cannot answer. See Permissions for the full model.

Install under WSL2

Inside your distribution, the standard installer works as on any Linux host:

Terminal window
curl -fsSL https://qialike.cn/install | bash
sudo apt install bubblewrap # gives the confined bash rung

Then verify both halves — the binary and the sandbox:

Terminal window
qialike --version
qialike --help

If bubblewrap cannot be installed, bash is still confined by the Landlock rung on a kernel ≥5.13 with that LSM enabled. Only when neither rung works do workspace-write / read-only bash calls fail closed with SANDBOX_UNAVAILABLE; where the executor offers no kernel confinement, per-call shell approval takes over. See Linux: SANDBOX_UNAVAILABLE.

Install on native Windows

A native Windows environment has no bash, so the curl | bash line does not work there.

npm — npm i -g @qialike/cli, which needs Node.js ≥ 18 first. This channel also updates itself and is removed with npm uninstall -g @qialike/cli.

Manual — download the archive and place qialike.exe yourself:

  1. Download qialike-windows-x64.zip from Releases (on ARM devices take -arm64; the mirror is gitcode.com/qialike/qialike/releases) — it is an archive, not a bare .exe.

  2. Unzip the single qialike.exe it contains into %USERPROFILE%\.dsh\bin\ — the installer’s default directory (anywhere else works too, as long as you remember where). qialike uninstall keeps that bin\ directory and the exe in it — Windows will not delete a running executable — and prints the command that removes it; see Uninstall.

  3. Add that directory to your user PATH, then reopen the terminal:

    Terminal window
    [Environment]::SetEnvironmentVariable('Path',
    "$env:USERPROFILE\.dsh\bin;" + [Environment]::GetEnvironmentVariable('Path', 'User'), 'User')
  4. Verify with qialike --version, then add a provider with /models.

Full steps for both routes: Install → Windows Terminal.

If you do have bash — Git Bash (Git for Windows), MSYS2 or Cygwin — the one-liner works there too: it detects MINGW/MSYS/CYGWIN and installs the windows-x64 (or windows-arm64) build. You can also build from source on Windows with Node.js ^22.19 || >=24, pnpm and bun, pointing DSH_HARNESS at a DeepSeek Harness checkout.

Updates on Windows depend on the install route

A hand-unpacked copy updates by hand only: a running .exe cannot be replaced and the installer is bash, so qialike upgrade --check only checks and prints the download link. Updating means downloading the new .zip, quitting qialike and replacing qialike.exe. An npm-installed copy does update automatically (patch releases installed silently, the same rule as Linux/macOS) and qialike upgrade hands the job to npm. See Updates → Updating, by how you installed.

Terminal choice

For either setup, use a modern terminal:

  • Windows Terminal — recommended, and on Windows please run qialike in this app rather than the old console window you get by launching cmd.exe / powershell.exe directly: cmd.exe / PowerShell is a shell (it interprets commands) while Windows Terminal is the terminal (it draws the interface), and the legacy window is visibly worse at true colour, mouse reporting, cursor shape and emoji fallback. Windows 11 ships it; on Windows 10 install it with winget install Microsoft.WindowsTerminal. See Install → Windows Terminal.
  • VS Code integrated terminal — works, and inherits Windows Terminal-class capabilities.
  • Legacy conhost.exe (the classic console window) — avoid it. It is the most likely to mishandle colour depth and escape sequences.

If colours still look off, force the depth rather than fighting the environment:

Terminal window
QIALIKE_COLOR=24bit qialike

Paths

Keep the workspace inside the Linux filesystem when you use WSL2 — for example ~/proj, not /mnt/c/...:

Terminal window
cd ~/proj
qialike --workspace ~/proj
  • /mnt/c/... is a cross-filesystem mount: file operations are much slower, and Unix permission bits do not map cleanly, which matters for the workspace-write fence.
  • In native Windows sessions, pass Windows paths and quote them if they contain spaces. Forward slashes usually work: qialike --workspace "C:/Users/me/proj".
  • Sessions are scoped to the workspace path, so the same project reached through two different path spellings (/home/me/proj vs /mnt/c/.../proj) produces two separate session lists.

Line endings

Windows tooling defaults to CRLF; the project’s scripts expect LF.

  • If bash scripts/install fails with \r: command not found or similar, the checkout has CRLF line endings. Re-clone with git config --global core.autocrlf input (in WSL) or git config --global core.autocrlf false, or convert the scripts with dos2unix.
  • Add a .gitattributes entry such as *.sh text eol=lf if your repository needs to be checked out from both Windows and Linux.
  • Pasted text is normalized by qialike itself: a bracketed paste converts CRLF to LF, and a pasted carriage return is treated as content, not as a submit. That keeps multi-line pastes intact.

Clipboard and keyboard

  • In WSL, Shift+right-click paste inside dialogs uses the Linux clipboard tools — install wl-clipboard (Wayland) or xclip/xsel (X11). Under WSLg, X11 tools are usually the easy path: sudo apt install xclip.
  • On native Windows, qialike reads the clipboard through powershell.exe -Command Get-Clipboard -Raw, so no extra tool is needed.
  • Windows Terminal passes Alt+Enter (newline), arrows, PgUp/PgDn and Home/End through correctly. If a terminal swallows Ctrl+T, use the Alt+T fallback to cycle reasoning effort.

Opening the web UI from Windows

qialike web starts the DeepSeek Harness browser UI through the installed dsh CLI, which must be at least the harness version embedded in your build (see Browser UI and headless / remote access). On Windows it resolves the npm dsh shim (.cmd / .bat), so the command runs through a shell; on POSIX it does not. If qialike runs inside WSL2 and you want to open the page in a Windows browser, rely on WSL2’s localhost forwarding (default port 3080) — or, from another machine, keep the loopback binding and tunnel over SSH. Binding the server is not an option: the web profile refuses --host 0.0.0.0 outright (error: --host 0.0.0.0 is intentionally not supported yet for safety: it would expose remote code execution to the network; use 127.0.0.1 instead).

Terminal window
# on the host running qialike (no local browser, so no --open)
qialike web --no-open # copy the printed http://127.0.0.1:3080/?token=… URL
# from the machine with the browser
ssh -L 3080:localhost:3080 user@host
# then open that printed URL

Open the URL the server printed — it carries the per-run auth token. Without it the server answers 401 dsh web authentication required; reopen the URL printed by dsh web., and the auth cookie is valid only for the authority it was issued for (127.0.0.1:3080 and localhost:3080 are different authorities), so pick one hostname and stay on it. --port <n> moves the port; if it is already taken, the second server exits with EADDRINUSE while your browser keeps talking to the older one, whose token you do not have.

Next steps