Skip to main content

Windows (Native) Guide

Minerva runs natively on Windows 10 and Windows 11 — no WSL, no Cygwin, no Docker. This page is the deep dive: what works natively, what's WSL-only, what the installer actually does, and the Windows-specific knobs you might need to touch.

If you just want to install, the one-liner on the landing page or Installation page is all you need. Come back here when something surprises you.

Want WSL instead?

If you prefer a real POSIX environment (for fork semantics, Linux-style file watchers, etc.), see the Windows (WSL2) Guide. Both coexist cleanly: native data lives under %LOCALAPPDATA%\minerva, WSL data lives under ~/.minerva.

Quick install​

Open PowerShell (or Windows Terminal) and run:

iex (irm https://tryimagent.com/install.ps1)

No admin rights required. The installer goes to %LOCALAPPDATA%\minerva\ and adds minerva to your User PATH — open a new terminal after it finishes.

Installer options (requires the scriptblock form to pass parameters):

& ([scriptblock]::Create((irm https://tryimagent.com/install.ps1))) -NoVenv -SkipSetup -Branch main
ParameterDefaultPurpose
-Sourcereleaserelease installs the SHA-256-verified release archive; git installs a git checkout (needs repository access; implied by a non-main -Branch, -Commit, or -Tag)
-BranchmainClone a specific branch (useful for testing PRs)
-CommitunsetPin install to a specific commit SHA (overrides -Branch)
-TagunsetPin install to a specific git tag (e.g. v0.14.0)
-NoVenvoffSkip venv creation (advanced — you manage Python yourself)
-SkipSetupoffSkip the post-install minerva setup wizard
-MinervaHome%LOCALAPPDATA%\minervaOverride data directory
-InstallDir%LOCALAPPDATA%\minerva\minerva-agentOverride code location

The installer auto-retries flaky git fetches and strips BOM from any downloaded install.ps1 payload, so a UTF-8 BOM picked up during HTTP transit no longer breaks the [scriptblock]::Create((irm ...)) form.

Desktop app​

There is no separate desktop installer to download: the desktop app is built from the release the one-liner above installed. Once it finishes, open a new terminal and run:

minerva desktop

The first run builds the app from that install and launches it; later runs just launch it. The desktop app and the minerva CLI share the same %LOCALAPPDATA%\minerva\minerva-agent install and %LOCALAPPDATA%\minerva data directory — switch between them freely. To repair a broken install, run the one-liner again, then minerva desktop.

Dependency bootstrap (dep_ensure)​

On first launch (and on demand when a missing tool is detected), Minerva runs a small Python bootstrapper — minerva_cli/dep_ensure.py — that checks for and lazily installs the non-Python dependencies it needs. On Windows, the relevant ones are:

DependencyWhy Minerva needs it
PortableGitProvides bash.exe for the terminal tool and git for in-session clones. Provisioned at install time, not by dep_ensure.
Node.js 26Required for the browser tool (agent-browser) and the TUI's web bridge.
ffmpegAudio format conversion for TTS / voice messages.
ripgrepFast file search — falls back to grep if unavailable.
npm packagesagent-browser, Playwright Chromium, and any per-toolset Node deps are installed once at first browser-tool use.

Each dep has a shutil.which(...)-style check; if a binary is missing and the run is interactive, dep_ensure offers to install it (deferring to scripts\install.ps1 -ensure <dep> for the actual install logic). Non-interactive runs (gateway, cron, headless desktop launches) skip the prompt and surface a clear this feature needs <dep> error instead.

What the installer actually does​

Top-to-bottom, in order:

  1. Bootstraps uv — Astral's fast Python manager. Installed to %USERPROFILE%\.local\bin.
  2. Installs Python 3.11 via uv. No existing Python needed.
  3. Installs Node.js 26 (winget if available, else a portable Node tarball unpacked under %LOCALAPPDATA%\minerva\node). Used for the browser tool.
  4. Installs portable Git — if git is already on PATH the installer uses it; otherwise it downloads a trimmed, self-contained PortableGit (~45 MB, from the official git-for-windows release) to %LOCALAPPDATA%\minerva\git. No admin, no Windows installer registry, no interference with anything else on the box.
  5. Downloads the latest release archive from the release channel, verifies its SHA-256, unpacks it to %LOCALAPPDATA%\minerva\minerva-agent, and creates a virtualenv inside it. (-Version 0.22.0 installs that published release instead of the latest; -Source git, a non-main -Branch, -Commit, or -Tag installs a git checkout instead.)
  6. Tiered uv pip install — tries .[all] first, falls back to progressively smaller sets ([all] minus known-broken extras → core only .) if a git+https dep flakes on rate-limited GitHub. Prevents "single flake drops you to a bare install" failure mode.
  7. Auto-installs messaging SDKs keyed off .env — if TELEGRAM_BOT_TOKEN / DISCORD_BOT_TOKEN / SLACK_BOT_TOKEN / SLACK_APP_TOKEN are present, runs python -m ensurepip --upgrade and targeted pip install calls so each platform's SDK is actually importable.
  8. Sets MINERVA_GIT_BASH_PATH to the resolved bash.exe so Minerva finds it deterministically in fresh shells.
  9. Adds %LOCALAPPDATA%\minerva\bin to User PATH and sets MINERVA_HOME=%LOCALAPPDATA%\minerva — exposes the minerva command (and points it at your data dir) after you open a new terminal. Only the minerva.exe / minerva-acp.exe launchers are copied into this bin directory; the full venv\Scripts is deliberately not placed on PATH so Minerva never shadows your own python command.
  10. Runs minerva setup — the normal first-run wizard (model, provider, toolsets). Skip with -SkipSetup.

Feature matrix​

Everything below runs natively on Windows.

FeatureNative WindowsWSL2
CLI (minerva chat, minerva setup, minerva gateway, …)✓✓
Interactive TUI (minerva --tui)✓✓
Messaging gateway (Telegram, Discord, Slack)✓✓
Cron scheduler✓✓
Browser tool (Chromium via Node)✓✓
MCP servers (stdio and HTTP)✓✓
Local Ollama / LM Studio / llama-server✓✓ (via WSL networking)
Auto-start at login✓ (schtasks)✓ (systemd)

How Minerva runs shell commands on Windows​

Minerva's terminal tool runs commands through Git Bash, same strategy Claude Code uses. This sidesteps the POSIX-vs-Windows gap without rewriting every tool.

Resolution order for bash.exe:

  1. MINERVA_GIT_BASH_PATH environment variable if set.
  2. %LOCALAPPDATA%\minerva\git\usr\bin\bash.exe (installer-managed PortableGit).
  3. %LOCALAPPDATA%\minerva\git\bin\bash.exe (older Git-for-Windows layout).
  4. System Git-for-Windows install (%ProgramFiles%\Git\bin\bash.exe, etc.).
  5. MSYS2, Cygwin, or any bash.exe on PATH as a last resort.

The installer sets MINERVA_GIT_BASH_PATH explicitly so fresh PowerShell sessions don't have to re-discover. Override it if you want Minerva to use a specific bash — for example, your system Git Bash or a WSL-hosted bash via a symlink.

Pitfall: MinGit's layout is different from the full Git-for-Windows installer — bash lives under usr\bin\bash.exe, not bin\bash.exe. Minerva checks both. If you're manually unpacking a MinGit zip, make sure you pick the non-busybox variant (MinGit-*-64-bit.zip, not MinGit-*-busybox*.zip) — busybox builds ship ash instead of bash and most coreutils are missing.

UTF-8 console on Windows​

Python's default stdio on Windows uses the console's active code page (usually cp1252 or cp437). Minerva's banner, slash-command list, tool feed, Rich panels, and skill descriptions all contain Unicode. Without intervention, any of that crashes with UnicodeEncodeError: 'charmap' codec can't encode character….

The fix is in minerva_cli/stdio.py::configure_windows_stdio(), called early in every entry point (cli.py::main, minerva_cli/main.py::main, gateway/run.py::main). It:

  1. Flips the console code page to CP_UTF8 (65001) via kernel32.SetConsoleCP / SetConsoleOutputCP.
  2. Reconfigures sys.stdout / sys.stderr / sys.stdin to UTF-8 with errors='replace'.
  3. Sets PYTHONIOENCODING=utf-8 and PYTHONUTF8=1 (via setdefault, so explicit user values win) so child Python subprocesses inherit UTF-8.
  4. Sets EDITOR=notepad if neither EDITOR nor VISUAL is set (see the Editor section below).

Idempotent. No-op on non-Windows.

Opt out: MINERVA_DISABLE_WINDOWS_UTF8=1 in the environment falls back to the legacy cp1252 stdio path. Useful for bisecting an encoding bug; unlikely to be the right setting in normal operation.

The editor (Ctrl+G, /prompt)​

Pressing Ctrl+G (Alt+G in VS Code/Cursor terminals) or typing /prompt opens your draft in an external editor. Pre-#21561 this silently did nothing on Windows: prompt_toolkit has a hardcoded POSIX-absolute fallback list (/usr/bin/nano, /usr/bin/pico, /usr/bin/vi, …) that never resolves on Windows — even with full Git for Windows installed.

Minerva's Windows stdio shim now sets EDITOR=notepad as a default. Notepad ships with every Windows install and works as a blocking editor — subprocess.call(["notepad", file]) blocks until the window closes.

User overrides still win (they're checked before the setdefault):

EditorPowerShell command
VS Code$env:EDITOR = "code --wait"
Notepad++$env:EDITOR = "'C:\Program Files\Notepad++\notepad++.exe' -multiInst -nosession"
Neovim$env:EDITOR = "nvim"
Helix$env:EDITOR = "hx"

The --wait flag on VS Code is critical — without it the editor returns immediately and Minerva gets a blank buffer back.

Set it permanently in your PowerShell profile:

# In $PROFILE
$env:EDITOR = "code --wait"

Or as a User environment variable in System Settings so every new shell picks it up.

Ctrl+Enter for newline in the CLI​

Windows Terminal passes Ctrl+Enter through as a dedicated key sequence. Minerva binds it to "insert newline" so you can compose multi-line prompts in the CLI without falling back to Esc-then-Enter. Works in Windows Terminal, VS Code integrated terminal, and any modern Windows console host that honors VT escape sequences.

On legacy cmd.exe consoles Ctrl+Enter collapses to plain Enter — use Esc Enter instead, or upgrade to Windows Terminal (it's free and installed by default on Windows 11).

Running the gateway at Windows login​

minerva gateway install on Windows uses Scheduled Tasks with a Startup-folder fallback. Registering the task may ask for UAC approval; the fallback needs no admin rights.

Install​

minerva gateway install

What happens under the hood:

  1. Writes a console-less .vbs launcher under %LOCALAPPDATA%\minerva\gateway-service\ and registers it with schtasks /Create /F /TN <task> /XML <task.xml> — a logon-triggered task (30-second delay, restarts on failure) that runs wscript.exe with standard, non-elevated permissions. Creating the task needs administrator approval on most accounts, so if your shell is not already elevated, minerva gateway install offers a UAC prompt first.
  2. If you decline the UAC prompt, or schtasks is blocked (access denied, timed out), it falls back to a small .vbs login item in %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup that starts the same launcher hidden. Same effect, without Task Scheduler's restart-on-failure.
  3. Starts the gateway (when you chose to start it now) as a detached console python.exe with a hidden console. The hidden console keeps its child processes (git, gh, node, …) from flashing windows, and a new process group keeps Ctrl+C in your shell from reaching it.

Flags used when spawning: CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW | CREATE_BREAKAWAY_FROM_JOB (retried without CREATE_BREAKAWAY_FROM_JOB when the parent job object forbids breakaway).

Manage​

minerva gateway status # Merged view: schtasks + Startup folder + running PID
minerva gateway start # Starts the gateway now (direct hidden launch, not via the task)
minerva gateway stop # Graceful SIGTERM equivalent (TerminateProcess via psutil)
minerva gateway restart
minerva gateway uninstall # Removes schtasks entry, Startup shortcut, pid file

minerva gateway status is idempotent — call it a thousand times in a row and it will never accidentally kill the gateway. (Pre-PR #21561 it silently did, via os.kill(pid, 0) colliding with CTRL_C_EVENT at the C level — see "process management internals" below if you care about the story.)

Why not a Windows Service?​

Services require admin rights to install and tie the gateway's lifecycle to machine boot, not user login. The typical Minerva user wants: log in → gateway available, log out → gateway gone. Scheduled Tasks do exactly that, and the gateway runs without elevation. If you genuinely want a service, use nssm or sc create manually — but you probably don't.

Data layout​

PathContents
%LOCALAPPDATA%\minerva\minerva-agent\Installed release (or git checkout with -Source git) + venv. Safe to Remove-Item -Recurse and reinstall.
%LOCALAPPDATA%\minerva\git\PortableGit (only if the installer provisioned it).
%LOCALAPPDATA%\minerva\node\Portable Node.js (only if the installer provisioned it).
%LOCALAPPDATA%\minerva\bin\The minerva / minerva-acp launchers and Minerva's managed uv.exe (the Python manager it uses for updates).
%LOCALAPPDATA%\minerva\ (root)Your config, auth, skills, sessions, logs (config.yaml, .env, skills\, sessions\, logs\, …). Survives reinstalls.

On native Windows the installer sets MINERVA_HOME=%LOCALAPPDATA%\minerva, so your data and the disposable install live under the same %LOCALAPPDATA%\minerva root: the install/runtime is the minerva-agent\, git\, node\, and bin\ subdirectories, while your data files sit directly in %LOCALAPPDATA%\minerva. Reinstalling only replaces the minerva-agent\ checkout, so your data survives — but because the two share a root, don't Remove-Item -Recurse %LOCALAPPDATA%\minerva if you want to keep your data; delete the minerva-agent\ subdirectory instead. Your data directory is identical in shape to a Linux ~/.minerva, so you can mirror it between machines.

Override MINERVA_HOME: set the environment variable to point at a different data dir (e.g. %USERPROFILE%\.minerva to match a Linux/WSL layout). Works the same as on Linux.

Browser tool​

The browser tool uses agent-browser (a Node helper) to drive Chromium. On Windows:

  • The installer puts agent-browser on PATH via npm.
  • shutil.which("agent-browser", path=...) picks up the .cmd shim automatically — CreateProcessW can't execute an extensionless shebang, so Minerva always resolves to the .CMD wrapper. Don't manually invoke the shebang script; always go through the .cmd.
  • Playwright Chromium is auto-installed on first run (npx playwright install chromium). If installation fails, minerva doctor surfaces it with a fix-it hint.

Running Minerva on Windows — practical notes​

PATH after install​

The installer adds %LOCALAPPDATA%\minerva\bin to your User PATH via [Environment]::SetEnvironmentVariable. Existing terminals don't pick this up — open a new PowerShell window (or Windows Terminal tab) after installation. Close-and-reopen, don't $env:PATH += … by hand unless you know what you're doing.

Verify:

Get-Command minerva # should print C:\Users\<you>\AppData\Local\minerva\bin\minerva.exe
minerva --version

Environment variables​

Minerva honors both $env:X (process-scope) and User environment variables (permanent, set in System Properties → Environment Variables). Setting API keys in %LOCALAPPDATA%\minerva\.env (your MINERVA_HOME) is the normal path — same as Linux:

OPENROUTER_API_KEY=sk-or-...
TELEGRAM_BOT_TOKEN=...

Don't put secrets in User environment variables unless you specifically want every Windows process to see them (it isn't what you want).

Windows-specific env vars​

These only affect native Windows installs:

VariableEffect
MINERVA_GIT_BASH_PATHOverride bash.exe discovery. Point at any bash — full Git-for-Windows, WSL bash via symlink, MSYS2, Cygwin. The installer sets this automatically.
MINERVA_DISABLE_WINDOWS_UTF8Set to 1 to disable the UTF-8 stdio shim and fall back to the locale code page. Useful for bisecting an encoding bug.
EDITOR / VISUALYour editor for /prompt and Ctrl+G. Minerva defaults to notepad if both are unset.

Uninstall​

From PowerShell:

minerva uninstall

That's the clean path — removes the schtasks entry, Startup folder shortcut, minerva.cmd shim, deletes %LOCALAPPDATA%\minerva\minerva-agent\, and trims the User PATH. It leaves the rest of %LOCALAPPDATA%\minerva\ alone (your config, auth, skills, sessions, logs) in case you're reinstalling.

To nuke everything:

minerva uninstall
Remove-Item -Recurse -Force "$env:LOCALAPPDATA\minerva"
# Also remove a legacy CLI/WSL data dir if you ever used one:
Remove-Item -Recurse -Force "$env:USERPROFILE\.minerva"

The minerva uninstall CLI subcommand also handles the case where the schtasks entry was registered under a different task name (older installs) — it searches by install path rather than by hardcoded task name.

Process management internals​

This is background material — skip unless you're debugging an "it's killing itself" weirdness.

On Linux and macOS, the POSIX idiom os.kill(pid, 0) is a no-op permission check: "is this PID alive and can I signal it?" On Windows, Python's os.kill maps sig=0 to CTRL_C_EVENT — they collide at integer value 0 — and routes it through GenerateConsoleCtrlEvent(0, pid), which broadcasts Ctrl+C to the entire console process group containing the target PID. That's bpo-14484, open since 2012. It won't be fixed because changing it would break scripts that depend on the current behavior.

Consequence: any codepath that said "check if this PID is alive" via os.kill(pid, 0) on Windows was silently killing the target. Minerva migrated every such site (14 across 11 files) to gateway.status._pid_exists(), which uses psutil.pid_exists() (which in turn uses OpenProcess + GetExitCodeProcess on Windows — no signals). If you're writing a plugin or patch, use psutil.pid_exists() directly or gateway.status._pid_exists() — never os.kill(pid, 0).

scripts/check-windows-footguns.py enforces this in CI: any new os.kill(pid, 0) call fails the Windows footguns (blocking) check unless the line carries a # windows-footgun: ok — <reason> marker.

Common pitfalls​

minerva: command not found right after install. Open a new PowerShell window. The installer added %LOCALAPPDATA%\minerva\bin to User PATH, but existing shells need to be restarted to pick it up. In the meantime you can run & "$env:LOCALAPPDATA\minerva\bin\minerva.exe".

WinError 193: %1 is not a valid Win32 application when running a tool. You hit a shebang-script invocation that bypassed the .cmd shim. Minerva resolves commands through shutil.which(cmd, path=local_bin) so PATHEXT picks up .CMD — if you're invoking the tool via a hardcoded path instead, switch to the .cmd variant (e.g., npx.cmd, not npx).

[scriptblock]::Create(...) fails with The assignment expression is not valid. Your download of install.ps1 picked up a UTF-8 BOM. The irm | iex form strips BOMs automatically; [scriptblock]::Create((irm ...)) does not. Re-run with the simple irm | iex form, or download the script manually and save it without a BOM via [IO.File]::WriteAllText($path, $text, (New-Object Text.UTF8Encoding $false)).

Gateway won't stay running after restart. Check minerva gateway status — it merges the schtasks entry, the Startup-folder shortcut (if used), and the live PID. If schtasks is registered but not running, group policy may be blocking ONLOGON triggers. Run schtasks /Query /TN Minerva_Gateway /V /FO LIST (named profiles use Minerva_Gateway_<profile>) to see the task's failure reason, or switch to the Startup-folder path by running minerva gateway uninstall, then minerva gateway install from a non-elevated shell and declining the UAC prompt.

/prompt still does nothing after setting $env:EDITOR. You set it in the current process only; close and reopen the shell, or set it at User scope in System Properties → Environment Variables. Verify with echo $env:EDITOR in a new PowerShell window.

Browser tool launches but tools time out. Chromium is auto-installed on first run. If the install failed (rate-limited GitHub, Playwright CDN hiccup), run minerva doctor — it will surface the missing Chromium and print the exact npx playwright install chromium command to fix it.

agent-browser fails with a weird Node version error. The installer provisions Node 26 at %LOCALAPPDATA%\minerva\node but your PATH may have an older system Node 18 first. Either move Minerva's node dir earlier on PATH, or delete the system install if you don't use Node elsewhere.

Chinese / Japanese / Arabic characters show as ? in the CLI. The UTF-8 stdio shim didn't activate. Check that MINERVA_DISABLE_WINDOWS_UTF8 is NOT set (Get-ChildItem env:MINERVA_DISABLE_WINDOWS_UTF8). If it's empty and you still see ?, the console host (very old cmd.exe) may not support UTF-8 at all — switch to Windows Terminal.

Gateway can't send Telegram photos — "BadRequest: payload contains invalid characters". This is unrelated to Windows but sometimes surfaces first there. Usually it means your file path contains unescaped backslashes in a JSON body. Telegram should be receiving paths Minerva normalizes, not raw Windows paths — if you're seeing this inside a custom plugin, make sure you're passing the Minerva-provided path, not str(Path(...)) from user input.

"Works on my other machine" encoding weirdness after git pull. If you edited Minerva config or a skill on Windows using a non-UTF-8 editor (Notepad on older Windows versions, some Chinese IMEs), the file may have been saved with a BOM. Minerva tolerates utf-8-sig on most config reads, but a BOM inside a folded YAML scalar (description: >) silently breaks YAML parsing. Re-save the file as plain UTF-8 without BOM.

Where to go next​