Windows runners
A Windows machine can be a runner in two ways. A native Windows runner executes Windows commands through the host's job-object supervisor. A WSL runner executes Linux commands inside a WSL distribution, on the Linux backend.
Native Windows serves Exec when its host configuration includes the enrolled peer transport, which deployment writes. The Windows open profile runs with the host account's OS permissions and is not a sandbox, as the security model explains. The Windows host reference lists the native host's paths, configuration and limits.
Native Windows
Native Windows deployment installs and updates the ax CLI and the host that serves messaging and native Windows execution. You run it from a Linux or macOS owner machine. Deployment then takes these steps, and you edit no configuration, run no separate enrollment command and start no task yourself:
- It generates the host identity on the Windows machine.
- It writes the host's complete private configuration, including the enrolled peer transport.
- It registers and starts the
ax-hosttask. - It publishes the root-signed caller grant.
- It proves execution with an authenticated
cmd.exediagnostic.
No signed Windows release is published, so a Windows deployment always needs a bundle built on Windows. On the Windows machine, prepare it from a working ax installation:
ax deploy bundle --out ./ax-win-bundle
Transfer the bundle directory to the owner machine you deploy from, and pass it to the deployment.
ax deploy ssh user@windows-host --name build --bundle ./ax-win-bundle/manifest.json
When the deployment finishes, run a job on the new host by its saved name:
ax exec run --host build -- cmd.exe /C echo Hello
- A Windows owner machine cannot run a full deployment, because the Exec client
broker that submits and observes the diagnostic is Unix-only. From Windows,
use
--planor--install-only, or run the deployment from Linux or macOS. - Deployment installs the launcher (
%LOCALAPPDATA%\ax\bin\ax.cmd) with a versioned release directory and an atomic release pointer. Repeating a deployment upgrades in place. Each install keeps the release it selected and the one it replaced and prunes older releases, exactly like the Linux and macOS layouts. - The host node key is generated on the Windows host and never leaves it. The owner's root private key, the namespace write secret and the deploying caller's credential stay on the owner machine.
- Deployment writes the private host configuration
(
%LOCALAPPDATA%\ax\server.json). It contains the unified top-level transport facts (peer_transport: trueplus the same names the Unix host uses), the host's enrollment credential, its registration grant and its discovery record. Deployment then publishes the root-signedExecGrantV1for the deploying caller. - It registers the scheduled task
ax-hostand starts it. The task runs in the installing account's interactive session at logon, with limited privileges, no time limit, and three restarts one minute apart. A conflicting task is refused, and--replacetakes it over. Installation alone registers the task but deliberately does not start it. exec_ready: trueis reported only after the authenticated Exec diagnostic. The host must answercapabilitiesas the prepared node and account, the connection must be connected, andcmd.exe /C echo <token>must reach a terminal success with complete retained stdout matching the token. A readiness record that the host reports is a startup diagnostic and never setsexec_ready.- The runner name and
ax exec rundefaults are saved only after that verification. A conflicting saved name is refused before the host is configured. If saving fails after verification, the result names the next step to take, and that step refers to the verified node instead of the stale alias. - Redeploying preserves the host identity and saved alias, issues a fresh
seven-day host credential, restarts the task and reports
authorization: {grant_revision, changed}. Running jobs stay observable across a restart of the host process or task. They do not survive a reboot or logoff. - The
openprofile runs with the host account's OS permissions. It inherits network and filesystem access. A kill-on-close Job Object contains the job's processes. Windows has no graceful console signal, so cancellation terminates the job's process tree immediately and does not honor a requested grace period. --plandescribes the stages without changing the host.--install-onlyinstalls the launcher and registers the task without provisioning or starting the host.
Paths, the full configuration and merge rules, the task definition, identity separation and limitations are on the Windows host reference.
Upgrade by redeploying with ax deploy ssh. ax undeploy ssh HOST stops and
unregisters the managed task. See Remove an installation.
Remove a native Windows installation
Remove an installation describes the removal command and its options.
On Windows, removal stops and unregisters the deploy-managed ax-host task and stops the host process serving the configured server.json. Stopping the owned task's host is part of undeploying it.
- When an owned task exists, removal collects and stops every managed host serving that configuration, without
--stop-services. - When no owned task exists, a separate managed host process that serves the configured
server.jsonblocks removal until--stop-servicespermits stopping it. --stop-servicesnever kills clients and never cancels jobs.- An installed
ax.exeprocess that does not serve the configuredserver.jsonalways blocks removal. Stop it yourself. - A missing task is not an error. A foreign or modified
ax-hosttask blocks removal.
Removal takes the provisioning lock, so it cannot run in the middle of a deployment. A crashed deployment or removal does not block later runs, because removal takes over a lock in some cases:
| Lock owner record | Removal |
|---|---|
| The owner process is dead, or its PID was reused | Takes the lock over |
| No owner record, and the lock is older than an hour | Takes the lock over |
| The owner process still exists, with a matching creation time or with none recorded | Never takes the lock over, whatever its age |
| The owner process is live, but its creation time cannot be read | Treats the owner as unverifiable and is blocked in the same way |
| The record is present but unreadable, malformed or shared | Refuses in place, and never takes the lock over by age |
A wedged but live owner blocks removal until that process is stopped. Remove its lock by hand only after you have confirmed the process is gone. For an unreadable, malformed or shared record, inspect it, and remove it by hand only once the provisioning process is confirmed gone. In both cases the lock fails closed.
WSL runners
A WSL runner executes Linux commands. To install the CLI on Windows itself, use the native Windows build. See Native Windows.
For a Windows OpenSSH endpoint that dispatches commands into WSL Bash, select that transport explicitly:
ax deploy ssh wsl-host --wsl-dispatcher --name wsl-build --bundle ./ax-linux-bundle/manifest.json
ax undeploy ssh wsl-host --wsl-dispatcher --plan
--wsl-dispatcher keeps the SSH command the same size every time. It sends a Bash loader, then a length-framed encoded command on stdin, then any binary data. It applies to probes, installation, provisioning and removal. A failed WSL probe is an error, and ax never falls back to a native Windows installation. For a Linux sshd running inside WSL, use an ordinary deployment instead.
Keep the distribution running
Windows must also keep the distribution alive after SSH disconnects. From an ax checkout, as the Windows user who owns the distribution, run the supplied script:
powershell.exe -NoProfile -File .\scripts\wsl-runner.ps1 -Action Install -Distribution Ubuntu
powershell.exe -NoProfile -File .\scripts\wsl-runner.ps1 -Action Status -Distribution Ubuntu
The script registers a task named ax-wsl-runner-Ubuntu and starts it immediately. The task starts again at that user's logon and runs wsl.exe --distribution Ubuntu --exec /bin/sleep infinity with the user's interactive token and limited privileges. It stores no password, has no time limit, and retries three times at one-minute intervals. Installing it again leaves a running task alone, and a conflicting task is refused. -TaskName selects a different managed task name.
The task keeps the distribution available after the user logs on. After a Windows reboot, it is not available until that logon. It does not make running jobs survive a Windows reboot or a WSL shutdown.
After deployment, close the SSH session. Verify the runner with ax exec info wsl-build and an ordinary ax job. The runner's Linux service reports give the WSL distribution as their boot scope, and say when the Windows keepalive task is required.
Remove the keepalive task
After you undeploy the runner, remove its task on Windows:
powershell.exe -NoProfile -File .\scripts\wsl-runner.ps1 -Action Remove -Distribution Ubuntu
Removal stops only the managed keepalive task. It never terminates the WSL distribution or other jobs. Install and remove the task with the same Windows account, distribution and task name.
Next steps
- Windows host reference: native Windows paths, configuration and limits.
- Install ax over SSH: build bundles, upgrade runners and remove an installation.