diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a90d2cc4..e13c732f 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -92,3 +92,29 @@ jobs:
run: npm ci
- name: Tauri debug build
run: npm run tauri -- build --debug --no-bundle
+
+ build-windows:
+ runs-on: windows-latest
+ needs:
+ - lint
+ - typecheck
+ - test-js
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: "20"
+ cache: "npm"
+ - uses: dtolnay/rust-toolchain@stable
+ - name: Install LLVM (bindgen)
+ run: choco install llvm -y --no-progress
+ - name: Configure LLVM (bindgen)
+ run: |
+ echo "LIBCLANG_PATH=C:\\Program Files\\LLVM\\bin" >> $env:GITHUB_ENV
+ echo "C:\\Program Files\\LLVM\\bin" >> $env:GITHUB_PATH
+ - name: Install dependencies
+ run: npm ci
+ - name: Doctor (Windows)
+ run: npm run doctor:win
+ - name: Tauri debug build (Windows)
+ run: npm run tauri -- build --debug --no-bundle --config src-tauri/tauri.windows.conf.json
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 6025a9f9..85f084de 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -219,12 +219,74 @@ jobs:
name: appimage-${{ matrix.arch }}
path: src-tauri/target/release/bundle/appimage/*.AppImage*
+ build_windows:
+ runs-on: windows-latest
+ environment: release
+ env:
+ TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
+ TAURI_SIGNING_PRIVATE_KEY_B64: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_B64 }}
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: setup node
+ uses: actions/setup-node@v4
+ with:
+ node-version: lts/*
+ cache: npm
+
+ - name: install Rust stable
+ uses: dtolnay/rust-toolchain@stable
+
+ - name: Install LLVM (bindgen)
+ run: choco install llvm -y --no-progress
+
+ - name: Configure LLVM (bindgen)
+ run: |
+ echo "LIBCLANG_PATH=C:\\Program Files\\LLVM\\bin" >> $env:GITHUB_ENV
+ echo "C:\\Program Files\\LLVM\\bin" >> $env:GITHUB_PATH
+
+ - name: install frontend dependencies
+ run: npm ci
+
+ - name: Write Tauri signing key
+ shell: bash
+ run: |
+ set -euo pipefail
+ python - <<'PY'
+ import base64
+ import os
+ from pathlib import Path
+
+ raw = base64.b64decode(os.environ["TAURI_SIGNING_PRIVATE_KEY_B64"])
+ home = Path.home()
+ target = home / ".tauri"
+ target.mkdir(parents=True, exist_ok=True)
+ (target / "codexmonitor.key").write_bytes(raw)
+ PY
+
+ - name: build windows bundles
+ shell: bash
+ run: |
+ set -euo pipefail
+ export TAURI_SIGNING_PRIVATE_KEY
+ TAURI_SIGNING_PRIVATE_KEY="$(cat "$HOME/.tauri/codexmonitor.key")"
+ npm run tauri:build:win
+
+ - name: Upload Windows artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: windows-artifacts
+ path: |
+ src-tauri/target/release/bundle/nsis/*.exe*
+ src-tauri/target/release/bundle/msi/*.msi*
+
release:
runs-on: ubuntu-latest
environment: release
needs:
- build_macos
- build_linux
+ - build_windows
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -244,6 +306,12 @@ jobs:
path: release-artifacts
merge-multiple: true
+ - name: Download Windows artifacts
+ uses: actions/download-artifact@v4
+ with:
+ name: windows-artifacts
+ path: release-artifacts
+
- name: Build latest.json
run: |
set -euo pipefail
@@ -345,6 +413,27 @@ jobs:
"signature": sig_path.read_text().strip(),
}
+ exe_candidates = sorted(artifacts_dir.rglob("*.exe"), key=lambda p: p.name.lower())
+ windows_installer = None
+ for candidate in exe_candidates:
+ lowered = candidate.name.lower()
+ if "setup" in lowered or "installer" in lowered:
+ windows_installer = candidate
+ break
+ if windows_installer is None and exe_candidates:
+ windows_installer = exe_candidates[0]
+ if windows_installer is None:
+ raise SystemExit("No Windows installer (.exe) found for latest.json")
+
+ win_sig_path = windows_installer.with_suffix(windows_installer.suffix + ".sig")
+ if not win_sig_path.exists():
+ raise SystemExit(f"Missing signature for {windows_installer.name}")
+
+ platforms["windows-x86_64"] = {
+ "url": f"https://github.com/Dimillian/CodexMonitor/releases/download/v${VERSION}/{windows_installer.name}",
+ "signature": win_sig_path.read_text().strip(),
+ }
+
payload = {
"version": "${VERSION}",
"notes": notes,
@@ -378,6 +467,8 @@ jobs:
release-artifacts/CodexMonitor.app.tar.gz \
release-artifacts/CodexMonitor.app.tar.gz.sig \
release-artifacts/*.AppImage* \
+ release-artifacts/nsis/*.exe* \
+ release-artifacts/msi/*.msi* \
release-artifacts/latest.json
- name: Bump version and open PR
diff --git a/PLAN.md b/PLAN.md
new file mode 100644
index 00000000..8909d902
--- /dev/null
+++ b/PLAN.md
@@ -0,0 +1,58 @@
+# Windows Support Execution Plan
+
+Source of truth for requirements: `SPEC.md`.
+This plan is **live** and tracks what has landed and what remains for the Windows milestone (auto-updater + dictation).
+
+## Workstream
+
+### 1) Docs
+
+- [x] Add `SPEC.md` (Windows scope, updater + dictation required).
+- [x] Keep `PLAN.md` current as work lands.
+
+### 2) Git safety + PR
+
+- [x] Push `feature/windows-support` to a fork remote and set upstream to avoid accidental `main` pushes.
+- [x] Open a draft PR early so CI runs on every push.
+
+### 3) Windows UX + path correctness
+
+- [x] Make “Reveal in Finder” platform-aware (Explorer on Windows).
+- [x] Fix path joining in the frontend so Windows absolute/relative paths behave.
+- [x] Make backend `open_workspace_in` work cross-platform (macOS/Windows/Linux).
+- [x] Make default “Open in” targets sensible on Windows (Explorer + command-based editors).
+- [x] Make default shortcuts Windows-friendly (Ctrl/Alt; avoid Cmd+Ctrl collapse).
+
+### 4) Dictation on Windows (required)
+
+- [x] Enable Whisper dictation on Windows (`whisper-rs` + `cpal`) by removing the Windows stub.
+- [x] Update Windows build checks (`doctor:win`) to require LLVM/Clang + CMake.
+- [x] Fix `doctor:win` dependency detection on Unix (no shell builtins).
+
+### 5) CI (required)
+
+- [x] Add a Windows CI job that runs a Tauri debug build with `src-tauri/tauri.windows.conf.json`.
+
+### 6) Release + updater (required)
+
+- [x] Enable Windows updater artifacts in `src-tauri/tauri.windows.conf.json`.
+- [x] Add a Windows release build job to `.github/workflows/release.yml`.
+- [x] Extend `latest.json` generation to include Windows URL + signature.
+
+## Validation (run after each step)
+
+- `npm run lint`
+- `npm run test`
+- `npm run typecheck`
+- Rust checks are executed in CI for macOS + Windows jobs added by this plan.
+
+## Manual checklist (Windows)
+
+- [ ] `npm run tauri:build:win` succeeds on Windows 10/11.
+- [ ] App launches and can open workspaces.
+- [ ] Adding a workspace succeeds when `codex --version` works in Windows Terminal.
+- [ ] “Reveal in Explorer” opens the right folder.
+- [ ] Shortcut hints use Ctrl/Alt labels and work on Windows.
+- [ ] Theme dropdown options are readable in Dark/Dim with Reduce Transparency off.
+- [ ] Auto-updater finds and applies the latest release.
+- [ ] Dictation works end-to-end (download → hold-to-talk → transcript).
diff --git a/README.md b/README.md
index 7773e668..4f50829a 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@

-CodexMonitor is a macOS Tauri app for orchestrating multiple Codex agents across local workspaces. It provides a sidebar to manage projects, a home screen for quick actions, and a conversation view backed by the Codex app-server protocol.
+CodexMonitor is a Tauri app for orchestrating multiple Codex agents across local workspaces. It provides a sidebar to manage projects, a home screen for quick actions, and a conversation view backed by the Codex app-server protocol.
## Features
@@ -31,7 +31,7 @@ CodexMonitor is a macOS Tauri app for orchestrating multiple Codex agents across
### Files & Prompts
-- File tree with search, file-type icons, and Reveal in Finder.
+- File tree with search, file-type icons, and Reveal in Finder/Explorer.
- Prompt library for global/workspace prompts: create/edit/delete/move and run in current or new threads.
### UI & Experience
@@ -40,13 +40,14 @@ CodexMonitor is a macOS Tauri app for orchestrating multiple Codex agents across
- Responsive layouts (desktop/tablet/phone) with tabbed navigation.
- Sidebar usage and credits meter for account rate limits plus a home usage snapshot.
- Terminal dock with multiple tabs for background commands (experimental).
-- In-app updates with toast-driven download/install, debug panel copy/clear, sound notifications, and macOS overlay title bar with vibrancy + reduced transparency toggle.
+- In-app updates with toast-driven download/install, debug panel copy/clear, sound notifications, plus platform-specific window effects (macOS overlay title bar + vibrancy) and a reduced transparency toggle.
## Requirements
- Node.js + npm
- Rust toolchain (stable)
-- CMake (required for native dependencies; Whisper/dictation uses it on non-Windows)
+- CMake (required for native dependencies; dictation/Whisper uses it)
+- LLVM/Clang (required on Windows to build dictation dependencies via bindgen)
- Codex installed on your system and available as `codex` in `PATH`
- Git CLI (used for worktree operations)
- GitHub CLI (`gh`) for the Issues panel (optional)
@@ -74,13 +75,13 @@ npm run tauri dev
## Release Build
-Build the production Tauri bundle (app + dmg):
+Build the production Tauri bundle:
```bash
npm run tauri build
```
-The macOS app bundle will be in `src-tauri/target/release/bundle/macos/`.
+Artifacts will be in `src-tauri/target/release/bundle/` (platform-specific subfolders).
### Windows (opt-in)
@@ -94,8 +95,8 @@ Artifacts will be in:
- `src-tauri/target/release/bundle/nsis/` (installer exe)
- `src-tauri/target/release/bundle/msi/` (msi)
-
-Note: dictation is currently disabled on Windows builds (to avoid requiring LLVM/libclang for `whisper-rs`/bindgen).
+
+Note: building from source on Windows requires LLVM/Clang (for `bindgen` / `libclang`) in addition to CMake.
## Type Checking
diff --git a/SPEC.md b/SPEC.md
new file mode 100644
index 00000000..66fdfed1
--- /dev/null
+++ b/SPEC.md
@@ -0,0 +1,92 @@
+# Windows Support Spec
+
+## Goal
+
+Ship a **fully functioning Windows version** of CodexMonitor with:
+
+- **Auto-updater** enabled and wired into the release workflow (`latest.json` includes Windows).
+- **Dictation** working on Windows (same UX + model management as other platforms).
+
+This spec is the source of truth for Windows support requirements and acceptance criteria.
+
+## Target Platforms
+
+- Windows 10/11, **x86_64** (GitHub Actions `windows-latest`).
+
+## Non-Goals (for this milestone)
+
+- Authenticode / EV code signing (nice-to-have; not required to be functional).
+- Windows ARM64 builds.
+
+## Functional Requirements
+
+### Updater (Required)
+
+- Windows release artifacts must be produced by CI and attached to GitHub Releases.
+- `latest.json` must include a **Windows platform entry** with:
+ - correct asset URL
+ - signature generated by Tauri updater signing
+- In-app updater must be enabled for Windows builds (same endpoints + pubkey as other platforms).
+- The updater entry for Windows uses the **NSIS installer** (`.exe` + `.exe.sig`) as the updater bundle.
+
+### Dictation (Required)
+
+Dictation must work on Windows with the same surface area as other platforms:
+
+- Model status: missing/downloading/ready/error
+- Model download/cancel/remove
+- Session lifecycle: start/listening/stop->processing/transcript/cancel
+- Emits the same Tauri events:
+ - `dictation-download`
+ - `dictation-event`
+
+Implementation choice for this milestone:
+
+- Use the existing Whisper-based implementation on Windows (via `whisper-rs` + `cpal`).
+
+### Windows UX Correctness (Required)
+
+- “Reveal in Finder” strings must be platform-aware (“Explorer” on Windows).
+- Opening paths in an editor or file manager must behave correctly on Windows.
+- Shortcut hints and formatting must be platform-aware on Windows (Ctrl/Alt labels; no macOS-only glyphs).
+- Settings selects (for example Theme) must remain readable in Dark/Dim with Reduce Transparency off.
+
+## Build & Tooling Requirements
+
+### Windows Build Prereqs (dev + CI)
+
+Required on Windows to build dictation (Whisper + bindgen):
+
+- CMake
+- LLVM/Clang (for `bindgen` / `libclang`)
+
+`npm run doctor:win` must fail fast with actionable instructions if missing.
+`npm run doctor:win` must correctly detect installed dependencies on Windows/macOS/Linux.
+
+## CI / Release Requirements
+
+### CI (Required)
+
+- Add a Windows job to `.github/workflows/ci.yml` that:
+ - installs deps
+ - runs a Windows Tauri debug build (`--no-bundle`) using the Windows config
+
+### Release (Required)
+
+Update `.github/workflows/release.yml` to include Windows:
+
+- Build Windows bundles on `windows-latest`
+- Upload `.msi` / `.exe` plus updater `.sig` artifacts
+- Include Windows in generated `latest.json`
+
+## Acceptance Criteria
+
+- `npm run tauri:build:win` succeeds on Windows.
+- Windows release workflow publishes installers and `latest.json` that enables in-app updates.
+- Dictation works on Windows end-to-end (model download → hold-to-talk → transcript).
+- Adding a workspace works when `codex --version` runs in Windows Terminal (Codex PATH handling is correct).
+- Repo checks pass:
+ - `npm run lint`
+ - `npm run test`
+ - `npm run typecheck`
+ - Rust checks executed in CI for Windows/macOS as configured
diff --git a/docs/changelog.html b/docs/changelog.html
index 52df64ca..d90c6c33 100644
--- a/docs/changelog.html
+++ b/docs/changelog.html
@@ -81,7 +81,7 @@
Changelog
Codex Monitor
-
macOS Codex agents orchestration, built by and for individuals who ship fast.
+
Desktop Codex agent orchestration, built by and for individuals who ship fast.
@@ -129,7 +129,7 @@
Skills + prompts
Updater + polish
-
Toast-driven updates, resizable panels, and a macOS overlay title bar.
+
Toast-driven updates, resizable panels, and platform-specific window chrome.
@@ -412,7 +412,7 @@
Ready to monitor every agent run?
Codex Monitor
-
macOS Codex agents orchestration, built by and for individuals who ship fast.
+
Desktop Codex agent orchestration, built by and for individuals who ship fast.
- Show a macOS notification when a long-running agent finishes while the window is unfocused.
+ Show a system notification when a long-running agent finishes while the window is unfocused.
- Commands receive the selected path as the final argument. Apps use macOS open
- with optional args.
+ Commands receive the selected path as the final argument.{" "}
+ {isMacPlatform()
+ ? "Apps open via `open -a` with optional args."
+ : "Apps run as an executable with optional args."}
@@ -3139,11 +3168,11 @@ export function SettingsView({
Config file
- Open the Codex config in Finder.
+ Open the Codex config in {fileManagerName()}.