Skip to content

Gemma Chat - (For Windows, Linux, Raspberry Pi): Ollama backend + installers - #28

Open
revdarkness wants to merge 6 commits into
ammaarreshi:mainfrom
revdarkness:windows
Open

Gemma Chat - (For Windows, Linux, Raspberry Pi): Ollama backend + installers#28
revdarkness wants to merge 6 commits into
ammaarreshi:mainfrom
revdarkness:windows

Conversation

@revdarkness

Copy link
Copy Markdown

Summary

Adds first-class Windows support by replacing the MLX-LM backend with a thin Ollama HTTP client. Mac/MLX path is left untouched in spirit (and could be reintroduced behind a platform check), but this PR is scoped as a Windows-only release line tagged v0.1.0-win.1.

  • Delete src/main/mlx.ts (Python venv + mlx_lm.server subprocess manager)
  • Add src/main/ollama.ts — locate/pull/warm + chat-stream client. Uses Ollama's OpenAI-compatible /v1/chat/completions so the SSE parser is identical to the original. Honors OLLAMA_HOST env var.
  • src/shared/types.tsAVAILABLE_MODELS now uses gemma3:{1b,4b,12b,27b} Ollama tags; DEFAULT_MODEL = gemma3:4b
  • src/main/workspace.tswsRunBash runs PowerShell on Windows (GEMMA_SHELL=bash opt-out for Git Bash users); deny list extended for Windows destructive patterns
  • src/main/index.ts — mac-only BrowserWindow options (titleBarStyle, vibrancy, trafficLightPosition) now guarded by process.platform === 'darwin'; icon picks .ico on win32
  • electron-builder.yml — added win + nsis x64 target with desktop/start-menu shortcuts
  • build/icon.ico generated from existing icon.png via png-to-ico
  • package.jsondist:win / dist:mac convenience scripts; description updated
  • README rewritten for Windows with Ollama install, model table, env vars, and a v0.2 llama.cpp roadmap note

The window-frame and shell choices are platform-conditional, so reintroducing the MLX backend on darwin in a future PR would be additive — none of the mac-only chrome was removed unconditionally.

Why Ollama instead of MLX

MLX is Apple-only. Ollama runs natively on Windows, ships its own GPU acceleration (CUDA / ROCm preview), and exposes the same OpenAI-compatible chat surface the original MLX server already targeted, so the chat-streaming code carried over with zero changes. It also removes the Python venv bootstrap entirely, which is the biggest source of first-run friction on Windows.

A v0.2 will add an optional bundled llama.cpp backend so users don't need to install Ollama separately.

Test plan

  • npm run typecheck (node + web) passes on Windows 11
  • npm run build (electron-vite) passes
  • npm run dist:win produces dist/gemma-chat-0.1.0-win.1-setup.exe (NSIS, x64) — local smoke
  • First-run flow: Ollama not installed → user-facing error with download link
  • First-run flow: Ollama running, model not pulled → streaming pull progress in setup UI
  • Chat mode: tokens stream, tool calls execute, web search + bash tool work under PowerShell
  • Build mode: file writes land in workspace dir, live preview iframe updates
  • Model switching via the header switcher pulls + warms a new tag
  • Verified on macOS that the mac code path still compiles (BrowserWindow opts are spread conditionally)

Supply-chain note

Ran npm audit + lockfile-integrity scan + install-hook review on the fork: lockfile is clean (663/663 entries with sha512- SRI hashes, all from registry.npmjs.org), six lifecycle scripts present and all attributable to known maintainers (electron, esbuild, fsevents, onnxruntime-node, protobufjs warning-only, sharp). The 15 audit advisories are routine electron 34 / electron-builder 25 transitive noise, addressable via npm audit fix --force to bump electron → 42 / electron-builder → 26.

Credits

All original design, UX, agent loop, XML tool protocol, live-streaming write logic, and overall product taste are @ammaarreshi's. This PR is a mechanical port for the Windows side and a credit/link added to the README. Happy to split into smaller commits, drop the README changes, or reshape this as a Linux+Windows PR with a runtime backend switch if you'd rather — your call.

🤖 Generated with Claude Code

revdarkness and others added 2 commits May 17, 2026 14:04
Initial v0.1.0-win.1 fork release. Replaces the macOS / Apple Silicon MLX-LM
backend with a thin Ollama HTTP client so the app runs on Windows (and
Linux) against any local Ollama daemon.

Backend
- Delete src/main/mlx.ts (Python venv + mlx-lm subprocess manager)
- Add src/main/ollama.ts (HTTP client: locateOllama, pullModel with
  streaming progress, warmModel, listLocalModels, chatStream over
  /v1/chat/completions). Honors OLLAMA_HOST env var.
- Rewire src/main/index.ts: ensureOllamaRunning() replaces
  ensureMLXRunning(); error message points users to ollama.com/download.

Shared types
- AVAILABLE_MODELS now uses gemma3:{1b,4b,12b,27b} Ollama tags.
- DEFAULT_MODEL = gemma3:4b.
- SetupStage retains 'starting-mlx' as a stable IPC name (now means
  "warm model into memory") so the renderer StageList keeps working.

Platform glue
- workspace.ts wsRunBash: PowerShell on Windows, /bin/bash elsewhere.
  GEMMA_SHELL=bash opt-out for Git Bash users. Deny list extended with
  Windows-side destructive patterns (format c:, rd /s /q c:, etc.).
- main/index.ts createWindow: titleBarStyle/vibrancy/trafficLights only
  applied on darwin; standard window frame on Win/Linux. Icon now picks
  build/icon.ico on win32, build/icon.png otherwise.
- tools.ts: User-Agent now matches the host OS.
- before-quit: stop the workspace HTTP server but leave Ollama (it's a
  shared system service).

Build
- electron-builder.yml: add win/nsis x64 target. Installer is
  per-machine-optional, opt-in install dir, desktop + start-menu
  shortcuts.
- build/icon.ico generated from build/icon.png via png-to-ico.
- package.json: dist:win + dist:mac convenience scripts, updated
  description, version 0.1.0-win.1.

Docs
- README rewritten for Windows: Ollama install path, Gemma 3 model
  table, npm run dist:win, OLLAMA_HOST + GEMMA_SHELL env vars,
  v0.2 llama.cpp roadmap note. Credit to @ammaar for original work.

Supply-chain audit (npm install + npm audit + lockfile/lifecycle
review): no integrity or registry-source issues, all 6 install hooks
belong to legitimate maintainers (electron, esbuild, fsevents,
onnxruntime-node, protobufjs, sharp). 15 advisories are routine
electron + electron-builder transitive noise, addressable later via
electron 42 / electron-builder 26 upgrades.

Typecheck and electron-vite build both pass clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two findings from local Windows smoke-test:

1. Electron 34's embedded Node 20.19 crashes in cjsPreparseModuleExports
   when an ESM main process imports the CJS `electron` module. Symptom:
   "TypeError: Cannot read properties of undefined (reading 'exports')"
   at node:internal/modules/esm/translators on app start. Root cause is
   package.json having "type":"module" (needed for the renderer) combined
   with the .js extension on the main bundle making Node treat it as ESM.

   Fix: force the main + preload bundles to emit as CommonJS with a .cjs
   extension via rollup output.format='cjs'. Renderer is untouched (still
   ESM, still uses React 19 + Vite as before). Updates:
   - electron.vite.config.ts: rollupOptions.output for main + preload
   - package.json: "main" -> "./out/main/index.cjs"
   - src/main/index.ts: preload path -> "../preload/index.cjs"

2. Ollama now ships `gemma4:latest` (8B Q4_K_M, 9.6 GB). Promote it to
   the recommended default since the upstream repo was named for Gemma 4
   and the original macOS/MLX path targeted Gemma 4 specifically. The
   gemma3:* tags remain as smaller alternatives.

Both fixes verified against gemma4:latest via curl smoke-tests on the
OpenAI-compatible /v1/chat/completions endpoint (non-streaming returns
clean JSON; streaming returns "data: {...}\n\n" SSE blocks ending with
"data: [DONE]" — matches the chatStream() parser shape exactly).

Note (not in code): if you hit this same "cannot read properties of
undefined" crash on a fresh Windows install and the CJS fix doesn't help,
check `echo %ELECTRON_RUN_AS_NODE%` — if set to 1, Electron skips its
native bootstrap and runs as plain Node, which makes require('electron')
return a path string. Common in shells configured for older Electron
tooling or some MCP setups. Unset it for development.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@revdarkness

Copy link
Copy Markdown
Author

Smoke-tested locally on Windows 11 + Node 20.19. Two follow-up commits pushed to revdarkness:windows:

  1. Node 20.19 ESM/CJS interop crash fix. With "type":"module" in package.json and the main bundle at out/main/index.js, Node treats the main process as ESM. Electron 34's embedded Node 20.19 then crashes in cjsPreparseModuleExports when our ESM bundle imports the CJS electron module — TypeError: Cannot read properties of undefined (reading 'exports'). Fix: emit main + preload as CommonJS with a .cjs extension via rollupOptions.output.format = 'cjs'. Renderer stays ESM/React/Vite as before. Same fix the wider electron-vite community has converged on for this Node version.

  2. gemma4:latest added as the recommended default. Ollama now publishes Gemma 4 (8B Q4_K_M, 9.6 GB) as gemma4:latest, which lines up with the upstream README's original intent. The gemma3:* tags remain as smaller alternatives.

Verified end-to-end against gemma4:latest: streaming data: {...}\n\n SSE chunks ending with data: [DONE] parse cleanly through the existing chatStream() reader. App launches, Welcome → Setup → chat flow loads.

Happy to split the CJS fix into its own PR if you'd prefer it land independently of the Windows port — it benefits any Node 20.19+ user, including the macOS path.

Also updated the GitHub repo About / description to mention Windows.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@revdarkness revdarkness changed the title Windows port: Ollama backend + NSIS installer (v0.1.0-win.1) Gemma Chat - (For Windows): Ollama backend + NSIS installer May 17, 2026
electron-builder.yml
- New `linux` block: AppImage (x64) + .deb (x64, arm64)
- arm64 .deb is the right artifact for Raspberry Pi 5 / Pi 4 64-bit OS
- .deb declares libnotify4 + libxtst6 + libnss3 runtime deps; Ollama
  itself is not an apt dep (install separately from ollama.com)
- desktop file metadata: Utility category, StartupNotify, MIME handler

package.json
- New scripts: `dist:linux`, `dist:linux:arm64`

README
- "Building the Installer" now covers Windows + Linux side-by-side
- New Raspberry Pi note: gemma3:1b or gemma4:cloud (Ollama Turbo) are
  the right model choices on Pi; local gemma4 8B is too slow even on
  Pi 5 16 GB. The Ollama HTTP client doesn't care whether the model
  is :cloud or local — it just hits OLLAMA_HOST.
- Roadmap updated: removed "Linux build target" (done), added
  pre-built release artifacts + OLLAMA_API_KEY as next-up items.

Source code untouched. The same ollama.ts client works on Windows,
Linux, and Mac without conditional logic — only the build target +
install instructions differ per platform.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@revdarkness revdarkness changed the title Gemma Chat - (For Windows): Ollama backend + NSIS installer Gemma Chat - (For Windows, Linux, Raspberry Pi): Ollama backend + installers May 17, 2026
revdarkness and others added 2 commits May 17, 2026 15:53
.github/workflows/release.yml builds installers for all platforms when
a vX.Y.Z tag is pushed, then publishes them to a GitHub Release.

Matrix:
- windows-latest  -> dist:win   -> NSIS .exe (x64)
- ubuntu-latest   -> dist:linux -> AppImage (x64) + .deb (x64, arm64)
- macos-latest    -> dist:mac   -> DMG (arm64)

Triggers:
- push tag v*.*.*    -> build + release
- workflow_dispatch  -> build only (no release; for sanity-checking)

Notable choices:
- Node 20 (Electron 34's embedded runtime); npm ci for reproducible installs
- Typecheck runs before build in every matrix slot — catches type
  regressions before we ship binaries
- electron-builder invoked with `--publish never`; the release job in
  the second stage does the publishing via softprops/action-gh-release,
  which handles attach + release-notes generation
- CSC_IDENTITY_AUTO_DISCOVERY=false to keep electron-builder from
  trying to find non-existent signing identities on macOS
- Concurrency: cancel-in-progress: false on release.yml so concurrent
  tag pushes don't race each other and produce half-published releases
- artifact retention: 14 days (workflow_dispatch debug builds expire;
  released artifacts live on the Release page indefinitely)

README: new "Pre-built Releases" section above the Roadmap pointing
users at the Releases page. Roadmap dropped the "pre-built artifacts"
item (done), added code-signing as the next-up item.

To cut the first release after this lands: `git tag v0.1.0-win.1 &&
git push origin v0.1.0-win.1`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
electron-builder's FPM-based .deb packager rejects a bare-string author
with "Please specify author 'email' in the application package.json".
NSIS and DMG packagers don't care. Promote `author` to the object form
{ name, email } using the GitHub noreply email as a no-PII placeholder.

Verified Win + Mac builds succeeded in the dry run (run 26002493516);
this is the only change needed to unblock the Linux matrix slot.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant