Repository navigation
Description
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.mdin-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/binetc. on Linux. - B8 — mitmdump absolute-path fallback list omits
/usr/bin/mitmdump(proxyServer.ts:636-637), the standard Linux location. Fix:command -vbefore the hardcoded list. - B9 —
caffeinatekeep-awake and the dictationFndefault binding have no Linux equivalent (guarded, degrade cleanly). Fix: wiresystemd-inhibit/ a platform-aware default binding. - B10 —
STATE_DIRignores$XDG_CONFIG_HOME(paths.ts:18) — per-user-correct but not XDG-honoring on Linux. Fix: honorXDG_CONFIG_HOMEwhen 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 ElectronBrowserWindow, 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)
- B1 → B2 → B3 — make it run (binaries, prebuild, build target).
- B4 + B5 + B6 — make it usable (keyboard, credentials, window chrome).
- 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
Juliusolsson05 commentedon Jul 7, 2026
Companion issue: the "any Mac, any user" hardening (actionable now) is #495. This issue is the parked Linux/Windows platform-enablement effort.
Juliusolsson05 commentedon Jul 7, 2026
.zipattached 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.
Juliusolsson05 commentedon Sep 27, 2026
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.