Skip to content

Portability: Linux/Windows platform enablement (Tier B/C — parked) #496

Open

Description

@Juliusolsson05

Why this exists

Companion to the "any-Mac hardening" issue linked below. That issue covers what breaks on a second Mac; this one is the genuine platform-enablement project — everything required for the app to actually run on Linux (and eventually Windows). Today the app is macOS-only by design: bundled tooling, credential storage, window chrome, and the keyboard layer are all mac-shaped.

This is intentionally parked — it's not a bug pass, it's a new-platform effort with a real cost. Filing it now so the failure points are captured while fresh; it should get its own explicit green-light and scoping before work starts.

Full audit writeup lives at temp/portability-audit-issue.md in-repo.


Findings

B1 · CRITICAL (Linux) — No Linux/Windows bundled binaries anywhere; getPlatformKey() returns null off-darwin

src/main/setup/runtimeTools.ts:84-102 · third_party/{mitmproxy,tmux,cloudflared}/manifest.json (only darwin-arm64 + darwin-x86_64)

On Linux, getPlatformKey() returns null → resolveBundledTool() yields null → mitmproxy (Claude proxy-streaming spine, #119), tmux (pane persistence, #120), and cloudflared (remote tunnel) are all absent. tmux/cloudflared have a no-PATH-fallback policy, so those features are simply dead; mitmproxy falls back to PATH but nothing's bundled. scripts/runtime-tools/fetch-*.mjs also build a linux-x64 key that has no manifest entry, so even fetching fails.

Fix: add linux-x86_64/linux-arm64 (and Windows) entries to each manifest with per-arch sha256 + URL templates, extend getPlatformKey, and teach the fetch/verify + copy-packaged-resources.mjs those platforms.

B2 · CRITICAL (Linux) — node-pty has no Linux prebuild; postinstall compiles it from source

package.json postinstall · node-pty prebuilds ship only darwin-* + win32-*

A fresh npm install on Linux compiles pty.node from source, requiring python3 + make + a C++ toolchain. On a box without build-essential, install fails at postinstall with no prebuilt fallback.

Fix: pin/verify a Linux prebuild per arch, or document the required toolchain.

B3 · CRITICAL (Linux) — No linux/win electron-builder target exists at all

electron-builder.yml (only a mac: block) · every package.json script is --mac; release.yml is macOS-only

There's no config path to produce a Linux/Windows artifact, and entitlements.mac.plist + hardenedRuntime are mac-specific.

Fix: add linux (AppImage/deb) and win (nsis) target blocks + matching runtime:prepare:* scripts, gated behind B1/B2.

B4 · HIGH — Primary global keydown handler is hard-bound to metaKey (Cmd) → entire keyboard surface dead on Linux/Windows

src/renderer/src/workspace/tile-tree/useKeybinds.ts:159 (const cmd = e.metaKey)

This handler drives the command palette, tile navigation, tab open/close, and dispatch-digit chords. On Linux/Windows the primary modifier is Ctrl (metaKey = Super/Win), so every shortcut becomes unreachable. The codebase already uses the right pattern elsewhere (CommandPalette.tsx:1088, DebugBundleNotePrompt.tsx:72 use metaKey || ctrlKey).

Fix: const cmd = e.metaKey || e.ctrlKey (or a platform-aware primaryModifier helper).

B5 · HIGH — Claude/Codex usage is hard-wired to macOS Keychain via security; hard throw off-darwin

src/main/usage/claudeUsage.ts:34-50 (throw 'Claude usage currently requires macOS Keychain credentials.' + security find-generic-password) · same shape in codexUsage.ts

The usage/limits panel can never populate on Linux/Windows — a permanent thrown error, with no fallback to Claude Code's on-disk credential file (~/.claude/.credentials.json) or libsecret/secret-tool.

Fix: add per-platform credential readers (file-based first, then libsecret/Windows Credential Manager); degrade to a clean "not available" state, not an exception. (The remote-auth secret in secret.ts already uses a portable 0o600 file pattern to mirror.)

B6–B10 · MEDIUM/LOW (Linux)

  • B6 — titleBarStyle: 'hiddenInset' (mainWindow.ts:155) is mac-only chrome; off-mac you get double chrome or a frameless window with no min/close/max controls the renderer never draws. Fix: platform-branch the title-bar style + inset padding.
  • B7 — PATH augmentation prepends only Homebrew dirs /opt/homebrew/bin, /usr/local/bin (toolchain.ts:93-94); on Linux these usually don't exist. Fix: append /usr/bin, ~/.local/bin etc. on Linux.
  • B8 — mitmdump absolute-path fallback list omits /usr/bin/mitmdump (proxyServer.ts:636-637), the standard Linux location. Fix: command -v before the hardcoded list.
  • B9 — caffeinate keep-awake and the dictation Fn default binding have no Linux equivalent (guarded, degrade cleanly). Fix: wire systemd-inhibit / a platform-aware default binding.
  • B10 — STATE_DIR ignores $XDG_CONFIG_HOME (paths.ts:18) — per-user-correct but not XDG-honoring on Linux. Fix: honor XDG_CONFIG_HOME when set. (Overlaps A10 in the companion issue.)
  • B11 (note) — The provider/terminal core (HeadlessTerminal, node-pty) is genuinely display-free, but the app shell is an Electron BrowserWindow, so a truly headless Linux/SSH host (no X/Wayland) can't launch the GUI at all. Inherent to the GUI; stated for expectation-setting.

Suggested execution order (only if green-lit)

  1. B1 → B2 → B3 — make it run (binaries, prebuild, build target).
  2. B4 + B5 + B6 — make it usable (keyboard, credentials, window chrome).
  3. B7–B10 — the polish tail.

Already-verified cross-platform (no work needed)

From the sweep: mitmproxy CA trust is env-var based (NODE_EXTRA_CA_CERTS/SSL_CERT_FILE/…), not Keychain / system-trust mutation — fully portable. Ports are dynamic (listen(0)). Atomic same-dir renames avoid EXDEV. Fonts have generic fallback chains. shell.openExternal/showItemInFolder use cross-platform Electron APIs (no raw xdg-open shelling). editorFs already path-separates on win32.


🤖 Drafted from a 6-agent portability sweep; see temp/portability-audit-issue.md.

Activity

  1. Juliusolsson05 commented on Jul 7, 2026

    @Juliusolsson05
    OwnerAuthor

    Companion issue: the "any Mac, any user" hardening (actionable now) is #495. This issue is the parked Linux/Windows platform-enablement effort.

  2. Juliusolsson05 commented on Jul 7, 2026

    @Juliusolsson05
    OwnerAuthor

    ⚠️ Do not download or run the .zip attached above.

    That archive was posted by an account unaffiliated with this project, within seconds of this issue being filed, and its message simply parrots the issue text back. This is a social-engineering malware pattern that scrapes newly-opened issues and drops a "fix" archive whose build/patch scripts execute the moment you apply them.

    Legitimate contributions arrive as reviewable pull requests, never as zipped attachments. The account has been blocked and the comment collapsed; please report the attachment to GitHub if you see it.

  3. Juliusolsson05 commented on Sep 27, 2026

    @Juliusolsson05
    OwnerAuthor

    Kept open and parked (owner decision, 2026-09-27). The triage findings are still accurate: no Linux/Windows build blocks, shortcuts only check Cmd, usage needs the Mac Keychain, and the window chrome is Mac-only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    class:C7-new-featureBug cluster of a recently shipped featuretype:featureNew capability (out of quality-loop fix scope)

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions