Files
OpenJarvis/deploy/windows/README.md
T
a79cd6f5e9 feat(windows): Phase-1 native install + scheduled-task service (#438)
Closes Phase-1 of #298 (Native Windows Support RFC).

Reverses the long-standing "native Windows is not supported" stance. PowerShell installer at `deploy/windows/install.ps1` (published to https://open-jarvis.github.io/OpenJarvis/install.ps1) plus a `jarvis-service.ps1` scheduled-task helper that mirrors `deploy/systemd/openjarvis.service` and `deploy/launchd/com.openjarvis.plist`. Loopback default (127.0.0.1, no API key) — same as launchd.

One-liner install:
    irm https://open-jarvis.github.io/OpenJarvis/install.ps1 | iex

Adversarial review caught and fixed two real bugs pre-commit:
1. `irm | iex` drops `param()` flags — added env-var fallbacks (OPENJARVIS_SKIP_SERVICE / OPENJARVIS_SERVICE / OPENJARVIS_FORCE).
2. Scheduled tasks don't inherit the registering session's env — the LAN-exposed `OPENJARVIS_API_KEY` path now persists the key to User scope so the task's logon environment can read it.

Supersedes #434 (the guidance-only "use WSL2" install.ps1).

Massive thanks to @SeCuReDmE-main-dev for the careful RFC #298 — the three-phase decomposition (install / service / shared-memory bridge) is exactly the right framing. This PR ships Phase-1 and Phase-2 of the RFC fused into one release; Phase-3 (shared memory bridge) remains future work.

Thanks also to @KadenBordeaux for raising #334 ("'bash' is not recognized as the name of a cmdlet"). That report is what made this whole Windows-support cluster a priority — without your bug report the unsupported stance would still be in the README. The friction you hit motivated #432 (numpy/python cap), #433 (CLI startup resilience), #436 (python discovery helpers), #437 (desktop launcher fix), and this PR.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 16:44:10 -07:00

127 lines
4.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# OpenJarvis on native Windows
Phase-1 of the native-Windows-support RFC (#298). Mirrors the Linux
(`deploy/systemd/`) and macOS (`deploy/launchd/`) deployments — but for
PowerShell, without WSL2 or Docker.
## One-liner install
In an elevated-or-regular PowerShell:
```powershell
irm https://open-jarvis.github.io/OpenJarvis/install.ps1 | iex
```
What it does:
1. Refuses non-Windows hosts and Windows < 10 1809.
2. Checks Python 3.10 3.13 (3.14 has no numpy wheels yet — see #432).
3. Checks `git` on PATH.
4. Installs `uv` (https://astral.sh/uv) if absent.
5. Clones the OpenJarvis repository to `%LOCALAPPDATA%\OpenJarvis`
(override with `$env:OPENJARVIS_HOME`).
6. Runs `uv sync --extra server` so the FastAPI server entry point is
importable.
7. Optionally prompts to register a scheduled task that auto-starts the
server at logon.
Flags (when invoked directly rather than via `irm | iex`):
| Flag | Effect |
|------|--------|
| `-Service` | Register the scheduled task without prompting |
| `-SkipService` | Don't prompt; don't register |
| `-Force` | Re-run all steps even if already done |
`irm | iex` can't pass `param()` args into a piped script string, so
the same knobs are honored via env vars when the corresponding flag is
absent:
```powershell
$env:OPENJARVIS_SKIP_SERVICE = '1'
irm https://open-jarvis.github.io/OpenJarvis/install.ps1 | iex
```
The available env vars: `OPENJARVIS_SKIP_SERVICE`, `OPENJARVIS_SERVICE`,
`OPENJARVIS_FORCE`. If you need richer control, save the script first
(`irm ... -OutFile install.ps1; .\install.ps1 -Force`).
## Manual scheduled-task setup
If you skipped the prompt during install, you can register / inspect /
remove the task with `jarvis-service.ps1`:
```powershell
$srv = "$env:LOCALAPPDATA\OpenJarvis\src\deploy\windows\jarvis-service.ps1"
# install (idempotent — replaces existing)
powershell -ExecutionPolicy Bypass -File $srv install
# status
powershell -ExecutionPolicy Bypass -File $srv status
# remove
powershell -ExecutionPolicy Bypass -File $srv uninstall
```
The task runs as the current user with `LogonType=Interactive` and
`RunLevel=Limited`. It restarts up to 3 times on failure (1-minute
gap), has no execution-time limit, and starts when available (catches
up if missed).
## Loopback vs LAN-exposed
By default the scheduled task binds `127.0.0.1` — reachable only from
this machine, no API key required. This matches launchd parity (see
`deploy/launchd/com.openjarvis.plist`).
To expose on your LAN:
```powershell
# 1. Generate an API key. The server REFUSES to bind 0.0.0.0 without one.
$env:OPENJARVIS_API_KEY = (uv run jarvis auth generate-key)
# 2. Re-register the task with -ListenHost 0.0.0.0.
powershell -ExecutionPolicy Bypass -File $srv install -ListenHost 0.0.0.0
```
`jarvis-service.ps1 install` refuses `-ListenHost 0.0.0.0` if
`$env:OPENJARVIS_API_KEY` is unset — same guard as the systemd unit's
`EnvironmentFile=/etc/openjarvis/env`.
## Parity table
| Concern | systemd | launchd | Windows |
|---------|---------|---------|---------|
| Service definition | `deploy/systemd/openjarvis.service` | `deploy/launchd/com.openjarvis.plist` | `deploy/windows/jarvis-service.ps1` (cmdlet-driven) |
| Default bind | `0.0.0.0` (with API key) | `127.0.0.1` (no API key) | `127.0.0.1` (no API key) |
| Restart on failure | `Restart=on-failure RestartSec=5` | `KeepAlive=true` | `RestartCount=3 RestartInterval=PT1M` |
| Auto-start | `multi-user.target` | `RunAtLoad=true` | `AtLogOn` trigger |
## Updating
To pull the latest:
```powershell
cd "$env:LOCALAPPDATA\OpenJarvis\src"
git pull --ff-only
uv sync --extra server
```
Or re-run the installer with `-Force`:
```powershell
irm https://open-jarvis.github.io/OpenJarvis/install.ps1 | iex
# (then re-run with the file directly, passing -Force)
```
## Uninstall
```powershell
powershell -ExecutionPolicy Bypass -File "$env:LOCALAPPDATA\OpenJarvis\src\deploy\windows\jarvis-service.ps1" uninstall
Remove-Item -Recurse -Force "$env:LOCALAPPDATA\OpenJarvis"
```
Uninstalling does NOT remove `uv` (it's a separate tool — you may have
other Python projects using it).