Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
d58a659
feat(win): cross-platform binary resolution + Windows build pipeline
Anurag-Wednesday Jun 27, 2026
56f608b
fix(llm): guarantee model is loaded before ready + cross-platform orp…
Anurag-Wednesday Jun 27, 2026
5862dcd
feat(models): dev control to stop/restart the local model server
Anurag-Wednesday Jun 27, 2026
5322c17
fix(win): fetch-win-binaries crashed on cosmetic listing, failing aft…
Anurag-Wednesday Jun 27, 2026
6759e12
Merge branch 'main' into feat/windows-support
Anurag-Wednesday Jul 11, 2026
10cd1fb
docs(win): add Windows support matrix + test plan/models
Anurag-Wednesday Jul 11, 2026
fc112dc
fix(win): pin bundled llama-server to b9838 to match the macOS engine
Anurag-Wednesday Jul 11, 2026
fd11183
fix(tools): budget tool schemas to context + surface server errors (B…
Anurag-Wednesday Jul 11, 2026
4226098
perf/fix(win): GPU (Vulkan) engine + CPU fallback, tighter tool budge…
Anurag-Wednesday Jul 11, 2026
c11d8f8
feat(win): device-aware copy + gate Pro to "coming soon" off macOS
Anurag-Wednesday Jul 15, 2026
d80b3da
fix(win): fetch a current sd asset (cpu x64), image binary was silent…
Anurag-Wednesday Jul 16, 2026
947d914
fix(embeddings): pin transformers cacheDir to a writable dir (was re-…
Anurag-Wednesday Jul 16, 2026
e59c30c
fix(win): set the Windows app icon (was defaulting to the Electron icon)
Anurag-Wednesday Jul 16, 2026
bccc194
refactor(models): remove the dev-only stop/restart model-server control
Anurag-Wednesday Jul 16, 2026
3d79573
feat(pro): tell non-Mac users Pro is coming soon on the upgrade screen
Anurag-Wednesday Jul 16, 2026
78c577d
ci(win): fold a Windows build into release.yml (versioned, published,…
Anurag-Wednesday Jul 16, 2026
1b04db3
ci(win): publish a permanent Windows download link (parity with Mac)
Anurag-Wednesday Jul 16, 2026
81509ff
docs(win): README lists Windows as a supported platform
Anurag-Wednesday Jul 16, 2026
4ef027f
test(tools): add effectiveContextSize to the llm mock (fixes CI test …
Anurag-Wednesday Jul 16, 2026
c1b7ad8
chore(pr): address review — CI credential hygiene, docs, brand copy
Anurag-Wednesday Jul 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 100 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ concurrency:
# free = unlicensed (pro tabs locked), a valid Keygen key unlocks in place (no
# re-download). The ASAR integrity fuse (electron-builder.yml) makes a tampered
# app.asar refuse to load — our local-first anti-tamper lever (we don't phone home).
# Actions are pinned to commit SHAs. Windows is parked.
# Actions are pinned to commit SHAs. macOS (build-mac) and Windows (build-win) share
# the one `version` job and publish to the same release; Windows runtimes come from
# fetch-win-binaries.ps1 rather than the macOS-only LFS binaries.
jobs:
# Resolve the channel + version. STABLE (manual promote) bumps the patch and
# commits it so main tracks the released version; BETA (every merge) stamps a
Expand Down Expand Up @@ -284,3 +286,100 @@ jobs:
NOTES_FILE: release-notes.md
RELEASE_URL: https://github.com/off-grid-ai/off-grid-ai-desktop/releases/tag/v${{ needs.version.outputs.version }}
run: node scripts/notify-slack-release.mjs

# Windows release build. Mirrors build-mac: it consumes the SAME resolved version
# + channel from the `version` job and publishes the NSIS installer plus the
# Windows electron-updater feed (latest.yml for stable, beta.yml for nightly) to
# the SAME GitHub release, so Windows and macOS ship as one version with working
# auto-update. Runs AFTER build-mac so the v$VERSION release already exists — this
# avoids a release-creation race between two concurrent `electron-builder --publish`
# runs. Windows native runtimes are fetched by scripts/fetch-win-binaries.ps1
# (the repo's LFS binaries are macOS-only).
build-win:
needs: [version, build-mac]
# windows-2022 = VS 2022 toolchain. windows-latest ships VS 2026, which node-gyp 11
# can't parse, breaking native-module (better-sqlite3) compiles. Pin until it catches up.
runs-on: windows-2022
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
ref: ${{ needs.version.outputs.sha }} # the exact bumped commit, same as build-mac
lfs: false # Windows runtimes come from fetch-win-binaries.ps1, not the LFS dylibs
persist-credentials: false # don't leave the token in .git/config for npm postinstall scripts
- name: Check out private pro source into pro/
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
repository: off-grid-ai/desktop-pro
token: ${{ secrets.PRO_REPO_TOKEN }}
path: pro
fetch-depth: 1
persist-credentials: false # keep PRO_REPO_TOKEN out of pro/.git/config
- name: Drop nested .git from pro/
shell: bash
run: rm -rf pro/.git # don't nest a repo inside the build tree
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: '20'
cache: 'npm'
# node-gyp (better-sqlite3-multiple-ciphers) fails on Python 3.13+; pin 3.12.
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: npm ci
- name: Fetch Windows native binaries (llama/whisper/sd/ffmpeg)
shell: pwsh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # raises the GitHub API rate limit
run: ./scripts/fetch-win-binaries.ps1
- name: Stamp build version
run: npm version "${{ needs.version.outputs.version }}" --no-git-tag-version --allow-same-version
- name: Build (typecheck + bundle)
run: npm run build
- name: Package & publish (NSIS installer + auto-update metadata)
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Optional Windows code signing — a no-op if the secrets are absent (the
# build still publishes, unsigned; SmartScreen warns until a cert is added).
CSC_LINK: ${{ secrets.WIN_CSC_LINK }}
CSC_KEY_PASSWORD: ${{ secrets.WIN_CSC_KEY_PASSWORD }}
run: |
# Same version tag as build-mac -> both platforms land on ONE release.
# stable -> latest.yml, published as a normal release (everyone)
# beta -> beta.yml (from the -beta suffix), published as a PRE-RELEASE
if [ "${{ needs.version.outputs.channel }}" = "stable" ]; then
npx electron-builder --win -c.publish.releaseType=release --publish always
else
npx electron-builder --win -c.publish.releaseType=prerelease --publish always
fi
# Permanent Windows download link — the Windows counterpart to the Mac
# OffGrid-latest.dmg alias. The versioned installer (off-grid-ai-<v>-setup.exe)
# changes name every release, so /releases/latest/download/<name> can't target
# it; upload a constant-named copy for a stable URL:
# https://github.com/off-grid-ai/off-grid-ai-desktop/releases/latest/download/OffGrid-latest-setup.exe
# The versioned installer + latest.yml updater feed are untouched, so auto-update
# is unaffected. --clobber replaces the copy from the prior run.
- name: Publish stable latest-setup.exe alias
if: needs.version.outputs.channel == 'stable'
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ needs.version.outputs.version }}
run: |
cp dist/*-setup.exe dist/OffGrid-latest-setup.exe
gh release upload "v$VERSION" dist/OffGrid-latest-setup.exe --clobber
# Constant nightly Windows link on the rolling 'nightly' pre-release (mirrors the
# Mac nightly.dmg link). build-win runs after build-mac, which already ensured the
# 'nightly' release exists — the fallback create is just belt-and-suspenders.
- name: Publish constant nightly-setup.exe link
if: needs.version.outputs.channel == 'beta'
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
cp dist/*-setup.exe dist/OffGrid-nightly-setup.exe
gh release view nightly >/dev/null 2>&1 || \
gh release create nightly --prerelease --title "Nightly (rolling)" \
--notes "Rolling nightly build, auto-updated on every change. Pre-release - expect rough edges."
gh release upload nightly dist/OffGrid-nightly-setup.exe --clobber
93 changes: 93 additions & 0 deletions .github/workflows/windows-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
name: Windows Build (branch)

# Standalone Windows build for the feat/windows-support branch. Kept separate
# from release.yml (macOS core+pro) on purpose: this neither bumps the version
# nor publishes to Releases — it packages the NSIS installer and uploads it as a
# workflow artifact you can download. Re-fold a windows-2022 job into release.yml
# once a build is verified on a real Windows machine.

on:
push:
branches:
- feat/windows-support
workflow_dispatch: # lets you trigger a build manually from the Actions tab

permissions:
contents: read

jobs:
build-win:
# windows-2022 = VS 2022 toolchain. windows-latest ships VS 2026 (VS 18),
# which node-gyp 11 can't parse — breaking native-module (better-sqlite3,
# node-llama-cpp) compiles. Pin until node-gyp catches up.
runs-on: windows-2022
env:
# True when the private-repo token is configured, so we bundle Pro (same as
# the Mac release build). Falsey on a fork / missing secret → core-only exe.
# Can't reference `secrets` directly in a step `if`, so surface it as env.
HAS_PRO_TOKEN: ${{ secrets.PRO_REPO_TOKEN != '' }}
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false # don't leave the token in .git/config for npm postinstall scripts
lfs: false # the repo's LFS binaries are macOS-only; Windows runtimes
# come from fetch-win-binaries.ps1, so don't pull ~235MB of
# dylibs we won't ship.
Comment thread
coderabbitai[bot] marked this conversation as resolved.

# Private pro source into pro/ → __OFFGRID_PRO__ true, so the exe bundles the
# Pro layer (mirrors release.yml). Needed to exercise the Pro "coming soon"
# gate on Windows. Pro stays license-gated at runtime; launch with
# OFFGRID_PRO=1 to force it on for testing without a license. Skipped (core
# build) when PRO_REPO_TOKEN isn't available.
- uses: actions/checkout@v4
if: env.HAS_PRO_TOKEN == 'true'
with:
repository: off-grid-ai/desktop-pro
token: ${{ secrets.PRO_REPO_TOKEN }}
path: pro
fetch-depth: 1
persist-credentials: false # keep PRO_REPO_TOKEN out of pro/.git/config
- name: Drop nested .git from pro/
if: env.HAS_PRO_TOKEN == 'true'
shell: bash
run: rm -rf pro/.git # don't nest a repo inside the build tree

- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

# node-gyp (better-sqlite3-multiple-ciphers) fails on Python 3.13+; pin 3.12.
- uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install dependencies
run: npm ci

- name: Fetch Windows native binaries (llama/whisper/sd/ffmpeg)
shell: pwsh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # raises the GitHub API rate limit
run: ./scripts/fetch-win-binaries.ps1

- name: Build (typecheck + bundle)
run: npm run build

- name: Package Windows installer (NSIS)
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Optional Windows code signing (no-op if absent → unsigned; SmartScreen
# will warn until you add a cert via these secrets).
CSC_LINK: ${{ secrets.WIN_CSC_LINK }}
CSC_KEY_PASSWORD: ${{ secrets.WIN_CSC_KEY_PASSWORD }}
run: npx electron-builder --win --publish never

- name: Upload installer artifact
uses: actions/upload-artifact@v4
with:
name: off-grid-ai-windows
path: |
dist/*.exe
dist/*.zip
if-no-files-found: error
33 changes: 29 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@
</p>

<p align="center">
<a href="https://github.com/off-grid-ai/desktop/releases/latest">Download (macOS)</a> ·
<a href="https://github.com/off-grid-ai/desktop/releases/latest">Download (macOS · Windows)</a> ·
<a href="docs/FEATURES.md">Features</a> ·
<a href="https://getoffgridai.co">getoffgridai.co</a> ·
<a href="https://getoffgridai.co/pay">Get Pro</a>
</p>

<p align="center">
<img alt="platform" src="https://img.shields.io/badge/macOS-Apple%20Silicon-black" />
<img alt="platform" src="https://img.shields.io/badge/Windows-x64-black" />
<img alt="license" src="https://img.shields.io/badge/license-AGPL--3.0-blue" />
<img alt="local" src="https://img.shields.io/badge/100%25-on--device-34D399" />
</p>
Expand Down Expand Up @@ -222,21 +223,45 @@ locked until a valid key is activated.

Grab the latest build from [Releases](https://github.com/off-grid-ai/desktop/releases/latest):

- **macOS** (Apple Silicon) — signed + notarized `.dmg`

macOS only for now.
- **macOS** (Apple Silicon) - signed + notarized `.dmg`
- **Windows** (x64) — NSIS installer (`.exe`)
Comment thread
Anurag-Wednesday marked this conversation as resolved.

## Build from source

```bash
git clone https://github.com/off-grid-ai/desktop.git
cd desktop
git lfs install && git lfs pull # pull the bundled native binaries (LFS) - REQUIRED
npm install
npm run dev # full app
npm run gateway # headless gateway only (:7878)
npm run build:mac # package a macOS app
```

> The `resources/bin/**` runtimes (llama.cpp, whisper.cpp, stable-diffusion.cpp,
> ffmpeg) are stored in **Git LFS**. Without `git lfs pull` you get 131-byte
> pointer stubs and every runtime spawn fails with `ENOEXEC`.

### Build for Windows

The committed LFS binaries are macOS-only; the Windows runtimes are fetched from
upstream releases at build time. **Build on a Windows machine** (native modules
must compile there - cross-building from macOS is not supported):

```powershell
git clone https://github.com/off-grid-ai/desktop.git
cd desktop
npm install
./scripts/fetch-win-binaries.ps1 # pull win64 llama/whisper/sd/ffmpeg into resources/bin
npm run dev # run locally, or:
npm run build:win # package the NSIS installer → dist\*-setup.exe
```

Prereqs on Windows: Node 20, Python 3.12 (node-gyp can't parse VS 2026 yet — use
the **VS 2022** Build Tools), and Git. CI also builds Windows on every push to
`feat/windows-support` (`.github/workflows/windows-build.yml`) and uploads the
installer as a downloadable artifact.

Stack: Electron 39 + React 19 + Tailwind v4 (electron-vite),
`better-sqlite3-multiple-ciphers` (encrypted local DB), `@lancedb/lancedb` (vectors),
bundled `llama.cpp` / `whisper.cpp` / `stable-diffusion.cpp` / `ffmpeg` in `resources/bin`.
Expand Down
Loading
Loading