Skip to content

AI tools, editor, and WSL isolation

The AI tooling is split into four focused modules. DeveloperEditor and OpenCodeExtensions are part of the normal developer workstation. AiTools and AiNixOsWsl are opt-in because they execute vendor installers or create a separate WSL distribution.

Inspect before changing anything

pwsh -NoProfile -File .\scripts\Set-AiToolsState.ps1 -Mode Plan
pwsh -NoProfile -File .\scripts\Set-AiToolsState.ps1 -Mode Test -Product OpenCode
pwsh -NoProfile -File .\scripts\Set-AiToolsState.ps1 -Mode Test -Json
pwsh -NoProfile -File .\scripts\Set-OpenCodeExtensionsState.ps1 -Mode Test
pwsh -NoProfile -File .\scripts\Set-DeveloperEditorState.ps1 -Mode Test
pwsh -NoProfile -File .\scripts\Set-AiNixOsWslState.ps1 -Mode Test
pwsh -NoProfile -File .\scripts\Test-WslTrustBoundary.ps1
pwsh -NoProfile -File .\scripts\Test-WslTrustBoundary.ps1 -Json

These commands are observational. The trust command does not start stopped distributions; a stopped distribution is reported as not inspected and returns drift instead.

OpenCode themes and OpenUltraCode

OpenCodeExtensions installs the three Cream Blue themes from pinned commit 7cef8d00dccd2c459df6bc1fe867a80bef668790 and selects cream-blue-cobalt in the global tui.json. It installs the hash-verified OpenUltraCode 0.1.3 release under the user's local data directory, publishes its commands, agents, and skill into the global OpenCode configuration, and registers the release-local plugin while preserving unrelated configuration and assets.

Inspect first, then explicitly reconcile as the current user:

pwsh -NoProfile -File .\scripts\Set-OpenCodeExtensionsState.ps1 -Mode Test
pwsh -NoProfile -File .\scripts\Set-OpenCodeExtensionsState.ps1 -Mode Ensure

Ensure downloads only the declared commit/release, verifies SHA-256 and the complete release inventory, and backs up managed files before replacing drift. Restart an already-running OpenCode TUI after reconciliation so it loads the selected theme and plugin.

Selected tools and sources

Product Location Declared channel
OpenCode Desktop Windows signed official release payload with pinned SHA-256, extracted to the standard per-user Programs path
OpenCode CLI Windows official global npm package opencode-ai
OpenCode CLI (sandboxed) NixOS-AI pinned Nix derivation in the complete verified Nix store
Claude Code Windows irm https://claude.ai/install.ps1 \| iex
Antigravity CLI (agy) Windows irm https://antigravity.google/cli/install.ps1 \| iex
Cursor CLI (cursor-cli) Windows irm 'https://cursor.com/install?win32=true' \| iex; vendor agent aliases are removed
Grok Build CLI (grok) Windows irm https://x.ai/cli/install.ps1 \| iex; retains its vendor agent compatibility entry point
Cline CLI Windows npm i -g cline
GitHub Copilot CLI Windows curl -fsSL https://gh.io/copilot-install \| bash (through Git Bash)
nono NixOS-AI brew install nono, pinned after review

Homebrew bootstrap and package maintenance run as the non-login ai-maint identity through the locked homebrew-fhs compatibility wrapper. The daily ai user cannot write that prefix. The installed nono bottle runs directly through the narrow NixOS nix-ld bridge rather than inside the maintenance FHS environment.

Claude Code is not declared through WinGet. If the state command observes the former Anthropic.ClaudeCode WinGet path, an explicit AiTools Ensure removes it before running the official installer. A failed installer stops the module; no alternate package source is used.

Install either additional CLI explicitly as the current Windows user:

pwsh -NoProfile -File .\scripts\Set-AiToolsState.ps1 -Mode Ensure -Product 'Antigravity CLI'
pwsh -NoProfile -File .\scripts\Set-AiToolsState.ps1 -Mode Ensure -Product 'GitHub Copilot CLI'

Antigravity uses its vendor PowerShell installer. Copilot uses Git for Windows' bash.exe to run its vendor curl -fsSL https://gh.io/copilot-install | bash installer; it does not use WSL's bash.exe or an npm fallback. Copilot's current Windows installer delegates to WinGet; the module publishes only a copilot.cmd shim in the existing per-user WinGet Links directory so copilot works in a new shell. It does not alter PATH or add Git Bash to it. Both commands download and execute vendor code only during explicit Ensure.

Cursor's vendor installer publishes both cursor-agent and the ambiguous agent command. The managed module retains the vendor binary but removes only %LOCALAPPDATA%\cursor-agent\agent.exe, agent.cmd, and agent.ps1, then publishes cursor-cli through the existing per-user WinGet Links directory. This preserves Grok's installed agent.exe without relying on user-PATH order. Re-run the focused Ensure after a Cursor update if its auto-updater recreates an agent alias.

Grok Build's canonical command is grok; its vendor agent.exe remains available for upstream compatibility. Do not use a bare agent to select an agent product—use cursor-cli or grok.

Install only the two native Windows OpenCode products as the current user:

pwsh -NoProfile -File .\scripts\Set-AiToolsState.ps1 -Mode Ensure -Product OpenCode

The focused Ensure installs the replacements first, then removes any former Scoop OpenCode Desktop and CLI packages. Both silent and interactive execution of the Desktop installer faulted on this workstation, so the command verifies its pinned hash and Authenticode signature, extracts the embedded application payload with inbox Windows tar.exe, and creates the normal Start-menu shortcut without executing the broken installer wrapper.

Omitting -Product selects every enabled Windows AI product. That broader Ensure executes network-delivered vendor code as the current Windows user:

.\Apply-Workstation.ps1 -Mode Ensure -Module AiTools,AiNixOsWsl

Review the Plan output first. Automated repository tests never run this command.

Developer editor

DeveloperEditor maintains stable Microsoft.VisualStudioCode, activates the pinned Berg theme, installs these exact extensions, and owns only the theme and two font keys in the user settings:

  • saoudrizwan.claude-dev (Cline)
  • ms-toolsai.jupyter
  • ms-python.python
  • GitHub.copilot-chat (the current stable VS Code bundled GitHub Copilot extension)

The resource installs exact extension teehausamberg.berg@0.0.4, whose manifest identifies https://github.com/jx22/berg, and requires VS Code to report it. It also verifies the contributed theme JSON against pinned commit 32e03bf59ae9408edc2d0c382a7003a57f1d2bc0 and SHA-256 290433bf27cd893a3f13bd3c5e01238f0885d1dbbad7934bfc20f9f63b3873e1. A downloaded file that VS Code has not discovered is drift, even when its digest matches. The managed workbench.colorTheme value is Berg Theme.

The fonts.terminalFamily value in ignored config.json remains the local font choice. Berkeley Mono is selected when Windows registers the family or when a font in the per-user Windows font directory exposes that exact embedded family name. Public configuration without that valid local family falls back to the installed Fira Code family. Existing settings are backed up and unrelated settings, extensions, profiles, and workspace configuration are preserved.

WSL trust matrix

Distribution role Interop Windows PATH Windows automount Daily sudo Intended content
ordinary Debian (TrustedUtility) on on on allowed trusted administration, Homebrew, Docker/Dagger
DevOps NixOS off off off off private SSH/cloud/Kubernetes credentials and IaC tools
Debian-MW off off off off hostile static inputs and rootless parser containers
AI NixOS off off off off private agent projects and OpenCode runtime state

Windows Terminal labels the two restricted NixOS profiles NixOS DevOps and NixOS AI; their underlying WSL distribution identities remain NixOS and NixOS-AI.

Ordinary Debian is trusted. Do not run autonomous AI agents or hostile parsers there, and do not store DevOps private keys there. The three restricted distributions receive tracked configuration through wsl.exe standard input rather than /mnt/c or /mnt/d.

DevOps credentials stay under the DevOps NixOS private Linux home. The trust check inspects only path resolution, owner, mode, kind, mounts, and sockets. It never reads a private key, token, or credential file. Shared Windows SSH configuration is now limited to ordinary Debian; DevOps NixOS, AI NixOS, and Debian-MW are excluded.

This is an intra-WSL workload boundary. The trusted Windows user and Windows administrators can still enter every distribution as root and access its VHD. It is not a boundary against a compromised Windows host, WSL kernel, or administrator.

Managed OpenCode launch

Choose the entry point according to the trust boundary needed for the task:

Task Command Boundary
Ordinary work in a Windows-accessible project opencode Native Windows user access
Autonomous or higher-risk work in a private AI project Invoke-OpenCodeSandbox.ps1 below Private NixOS-AI VHD plus verified nono policy

The native CLI is intentionally convenient and is not confined by the Nix/nono policy. Use the sandbox command when the project or agent activity needs the narrower filesystem, credential, socket, and network boundary.

Keep AI projects in the private AI VHD beneath /home/<ai-user>/projects. Windows VS Code can open the distribution explicitly. The guest does not receive a Windows drive mount.

pwsh -NoProfile -File .\scripts\Invoke-OpenCodeSandbox.ps1 `
  -Project /home/ai/projects/example `
  -CheckOnly

Remove -CheckOnly only after the preflight is compliant. The immutable launcher checks the maintenance-owned nono binary, exact root-owned profile hash, nono setup --check-only, secure Landlock TCP rule support, representative credential/host/socket denials, and a dry-run. It then runs opencode through nono; it never falls back to a direct launch.

The AI generation copies WSL resolver data into an independent /etc/resolv.conf and removes the cross-distribution /mnt/wsl mount during boot. The tracked policy records the official nolabs-ai/opencode lineage, extends nono's conservative default profile, and selects the installed developer proxy policy plus the reviewed provider/domain allowlist. The WSL2 insecure_proxy fallback is not enabled. If secure network enforcement is unavailable, the managed launch is blocked before OpenCode starts.

Debian-MW case transfer

Debian-MW no longer needs a host mount. Import and export are explicit streamed state changes:

pwsh -NoProfile -File .\scripts\Import-MalwareCase.ps1 `
  -Source D:\Cases\input `
  -CaseId case-20260817

pwsh -NoProfile -File .\scripts\Export-MalwareCase.ps1 `
  -CaseId case-20260817 `
  -Destination D:\Cases\case-20260817-results

Import refuses an existing case, reparse points, links, traversal-like names, devices, pipes, and sockets; it compares every SHA-256 before committing the private case directory. Export performs the corresponding guest and Windows staging checks and refuses an existing destination. The receipts contain paths, sizes, and hashes—not evidence bytes.