{"id":43118463,"url":"https://github.com/johnzfitch/claude-cowork-linux","last_synced_at":"2026-04-01T22:24:27.482Z","repository":{"id":332578309,"uuid":"1134247238","full_name":"johnzfitch/claude-cowork-linux","owner":"johnzfitch","description":"Run Claude Desktop’s Cowork mode natively on Linux — no macOS or VM required","archived":false,"fork":false,"pushed_at":"2026-03-16T07:04:18.000Z","size":864,"stargazers_count":79,"open_issues_count":3,"forks_count":17,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-03-16T08:46:05.373Z","etag":null,"topics":["anthropic","arch-linux","asar","aur","claude","claude-ai","claude-api","claude-code","claude-desktop","cowork","desktop-app","electron","linux","local-agent-mode","native-module-stub","nodejs","wayland","x11"],"latest_commit_sha":null,"homepage":"https://github.com/johnzfitch/claude-cowork-linux/releases","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/johnzfitch.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-14T13:08:48.000Z","updated_at":"2026-03-16T07:59:23.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/johnzfitch/claude-cowork-linux","commit_stats":null,"previous_names":["johnzfitch/claude-cowork-linux"],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/johnzfitch/claude-cowork-linux","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnzfitch%2Fclaude-cowork-linux","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnzfitch%2Fclaude-cowork-linux/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnzfitch%2Fclaude-cowork-linux/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnzfitch%2Fclaude-cowork-linux/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/johnzfitch","download_url":"https://codeload.github.com/johnzfitch/claude-cowork-linux/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnzfitch%2Fclaude-cowork-linux/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31292639,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T21:15:39.731Z","status":"ssl_error","status_checked_at":"2026-04-01T21:15:34.046Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["anthropic","arch-linux","asar","aur","claude","claude-ai","claude-api","claude-code","claude-desktop","cowork","desktop-app","electron","linux","local-agent-mode","native-module-stub","nodejs","wayland","x11"],"created_at":"2026-01-31T19:08:41.471Z","updated_at":"2026-04-01T22:24:27.436Z","avatar_url":"https://github.com/johnzfitch.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n\u003cimg src=\"https://github.com/user-attachments/assets/b50a50bb-2404-4153-a312-aa5784a16928\" alt=\"Claude Cowork for Linux (Unofficial)\" width=\"800\"\u003e\n\n # Claude Cowork on Linux\n ### No macOS, no VM required.\n\n\u003cbr\u003e\n\n![Platform](https://img.shields.io/badge/platform-Linux%20x86__64-blue?style=flat-square)\n![Version](https://img.shields.io/badge/version-v4.0.0-brightgreen?style=flat-square)\n![Tested](https://img.shields.io/badge/tested-Arch%20Linux-1793D1?style=flat-square\u0026logo=archlinux\u0026logoColor=white)\n![Status](https://img.shields.io/badge/status-Working-success?style=flat-square)\n![License](https://img.shields.io/badge/license-MIT-green?style=flat-square)\n\n**[Quick Start](#-quick-start)** · **[How It Works](#-how-it-works)** · **[Manual Setup](#-manual-setup)** · **[Troubleshooting](#-troubleshooting)**\n\n\u003c/div\u003e\n\n---\n\n## ![](.github/assets/icons/info-24x24.png) Overview\n\nClaude Cowork is a special Claude Desktop build that works inside a folder you point it at—it reads, writes, and organizes files there while it runs a plan. Cowork is currently a **macOS-only preview** backed by a sandboxed Linux VM; this repo reverse-engineers and stubs the macOS-native pieces so Cowork can run directly on Linux (x86_64)—no VM and no macOS required. The stub translates VM paths to host paths so Cowork points at the right files on Linux.\n\n**How it works:**\n\n| Step | Description |\n|:-----|:------------|\n| ![](.github/assets/icons/script-24x24.png) **Stubbing** | Replace macOS-only native modules (`@ant/claude-swift`, `@ant/claude-native`) with JavaScript |\n| ![](.github/assets/icons/console-24x24.png) **Direct Execution** | Run the Claude Code binary directly (no VM needed—we're already on Linux!) |\n| ![](.github/assets/icons/translation-24x24.png) **Path Translation** | Convert VM paths to host paths transparently |\n| ![](.github/assets/icons/platform-24x24.png) **Platform Spoofing** | Send macOS headers so the server enables the feature |\n\n---\n\n## ![](.github/assets/icons/status-24x24.png) Status\n\n- **Unofficial research preview**: This is reverse-engineered and may break when Claude Desktop updates.\n- **Linux support**: Currently targets **Linux x86_64**. Wayland: auto-detected via `$WAYLAND_DISPLAY` / `$XDG_SESSION_TYPE` (Ozone backend).\n- **Access**: Requires a Claude account. The installer auto-downloads the Claude Desktop DMG; no macOS machine needed.\n- **Tests**: 215+ test cases across 18 test files validating IPC, path translation, security, and session persistence.\n\n---\n\n## ![](.github/assets/icons/platform-24x24.png) Compatibility\n\n| Distro | Desktop | Status | Notes |\n|:-------|:--------|:-------|:------|\n| **Arch Linux** | Hyprland (Wayland) | Tested | Primary dev environment |\n| **Arch Linux** | KDE Plasma (Wayland) | Expected | KDE Wallet exposed via SecretService D-Bus |\n| **Arch Linux** | GNOME (Wayland) | Expected | Global shortcuts require manual DE config (GNOME lacks portal support) |\n| **Ubuntu 22.04+** | GNOME / X11 | Expected | gnome-keyring provides SecretService |\n| **Fedora 39+** | GNOME / KDE | Expected | May need `p7zip-plugins` for DMG extraction |\n| **Debian 12+** | Any | Expected | `p7zip-full` in apt |\n| **NixOS** | Any | Untested | Electron + bwrap sandboxing may need extra config |\n| **openSUSE** | Any | Tested | Uses `7zip` package (not `p7zip`); `nodejs-default` for Node.js |\n\n**Known caveats:**\n- Wayland compositors that don't implement the `GlobalShortcuts` portal (GNOME) won't have global hotkey support -- set a custom shortcut in your DE settings instead.\n- If `gnome-keyring` or another SecretService provider isn't running, the launcher falls back to `--password-store=basic` (credentials stored on disk, not in a keyring).\n- The `/sessions` root symlink requires `sudo` once during install. If your distro restricts root symlinks differently, point it manually: `sudo ln -s \"$HOME/.config/Claude/local-agent-mode-sessions/sessions\" /sessions`.\n\nRun `./install.sh --doctor` (or `claude-desktop --doctor`) after install to validate your environment.\n\n---\n\n## ![](.github/assets/icons/checkbox-24x24.png) Requirements\n\n- **Linux x86_64** (tested on Arch Linux, kernel 6.18.13)\n- **Node.js 18+** / npm\n- **Electron** (system package or npm global)\n- **asar** (`npm install -g @electron/asar`)\n- **p7zip** (to extract the macOS DMG; openSUSE uses `7zip` instead)\n- **bubblewrap** (sandbox isolation)\n- **Python 3.11+** (optional, for `enable-cowork.py` patching — the installer uses Node.js to download DMGs)\n- **Claude Pro** (or higher) subscription for Cowork access\n- **Secret service provider** (optional) -- gnome-keyring, KDE Wallet, or KeePassXC for secure credential storage. Without one, the launcher falls back to `--password-store=basic`.\n\n---\n\n## ![](.github/assets/icons/rocket-24x24.png) Quick Start\n\n### Method 1: install.sh (recommended)\n\n```bash\ngit clone https://github.com/johnzfitch/claude-cowork-linux.git\ncd claude-cowork-linux\n./install.sh          # auto-downloads the latest DMG via Node.js\nclaude-desktop\n```\n\n### Method 2: AUR (Arch Linux)\n\n```bash\nyay -S claude-cowork-linux       # auto-downloads the latest DMG\n```\n\n### Method 3: curl pipe\n\n```bash\nbash \u003c(curl -fsSL https://raw.githubusercontent.com/johnzfitch/claude-cowork-linux/master/install.sh)\n```\n\nThe installer automatically downloads the latest Claude Desktop DMG using Node.js (`scripts/fetch-dmg.js`). You can also provide a DMG manually:\n\n```bash\n./install.sh ~/Downloads/Claude-*.dmg\n# or\nCLAUDE_DMG=~/Downloads/Claude-1.1.4010.dmg ./install.sh\n```\n\n\u003e [!IMPORTANT]\n\u003e This repo does not include Anthropic's proprietary code. The installer downloads it directly from Anthropic's CDN.\n\n---\n\n## ![](.github/assets/icons/architecture-24x24.png) Architecture\n\n```\n┌─────────────────────────────────────────────────────────────────┐\n│                     Claude Desktop (Electron)                   │\n├─────────────────────────────────────────────────────────────────┤\n│  @ant/claude-swift (STUBBED)                                    │\n│  ├── vm.setEventCallbacks() → Register process event handlers   │\n│  ├── vm.startVM() → No-op (we're already on Linux)              │\n│  ├── vm.spawn() → Delegates to session orchestrator             │\n│  ├── vm.kill() → Kills spawned processes                        │\n│  └── vm.writeStdin() → Writes to process stdin                  │\n├─────────────────────────────────────────────────────────────────┤\n│  @ant/claude-native (STUBBED)                                   │\n│  ├── AuthRequest → Opens system browser (xdg-open)              │\n│  └── Platform helpers → Minimal compatibility shims             │\n├─────────────────────────────────────────────────────────────────┤\n│  stubs/cowork/ — Orchestration Layer (15 modules)               │\n│  ├── session_orchestrator.js   → Coordinates spawn lifecycle   │\n│  ├── asar_adapter.js            → Asar IPC API compatibility    │\n│  ├── process_manager.js         → Process lifecycle \u0026 I/O       │\n│  ├── resume_coordinator.js      → Session resume logic          │\n│  ├── sessions_api.js            → Session CRUD operations       │\n│  ├── session_store.js           → In-memory session state       │\n│  ├── transcript_store.js        → Transcript persistence        │\n│  ├── file_registry.js           → Working directory tracking    │\n│  ├── file_watch_manager.js      → File change detection         │\n│  ├── stream_protocol.js         → JSON-RPC stream parsing       │\n│  ├── credential_classifier.js   → Token leak prevention         │\n│  ├── eipc_channel.js            → EIPC message protocol         │\n│  ├── ipc_tap.js                 → IPC channel discovery         │\n│  ├── dirs.js                    → XDG directory resolution      │\n│  └── file_identity.js           → Path normalization            │\n├─────────────────────────────────────────────────────────────────┤\n│  Claude Code Binary                                             │\n│  └── Resolved from ~/.local/bin, mise/asdf shims, PATH, etc.   │\n│      (launch.sh replaces macOS Mach-O binary with Linux symlink)│\n└─────────────────────────────────────────────────────────────────┘\n```\n\n### Path Translation\n\nThe stub translates VM paths to host paths:\n\n| VM Path | Host Path |\n|:--------|:----------|\n| `/usr/local/bin/claude` or `claude` | Resolved via `~/.local/bin/claude`, `~/.config/Claude/claude-code-vm/{version}/claude`, or PATH |\n| `/sessions/...` | `~/.config/Claude/local-agent-mode-sessions/sessions/...` |\n\n### Mount Symlinks\n\nWhen you select a folder in Cowork, the stub creates symlinks to make it accessible at the expected VM path:\n\n```\n~/.config/Claude/local-agent-mode-sessions/sessions/\u003csession-name\u003e/mnt/\n├── \u003cfolder\u003e  → /home/user/path/to/selected/folder (symlink)\n├── .claude   → ~/.config/Claude/local-agent-mode-sessions/.../session/.claude (symlink)\n├── .skills   → ~/.config/Claude/local-agent-mode-sessions/skills-plugin/... (symlink)\n└── uploads/  (directory for file uploads)\n```\n\nThe `additionalMounts` parameter from Claude Desktop provides the mapping between mount names and host paths.\n\n\u003e [!NOTE]\n\u003e The Claude Code binary expects `/sessions` to exist. `install.sh` creates `/sessions` as a symlink into `~/.config/Claude/local-agent-mode-sessions/sessions` (requires `sudo` once) so you don't need a world-writable root directory.\n\n---\n\n## ![](.github/assets/icons/how-it-works-24x24.png) How It Works\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e1. Platform Spoofing\u003c/strong\u003e\u003c/summary\u003e\n\nThe app sends these headers to Anthropic's servers:\n\n```javascript\n'Anthropic-Client-OS-Platform': 'darwin'\n'Anthropic-Client-OS-Version': '14.0'\n```\n\nThis makes the server think we're on macOS 14 (Sonoma), enabling Cowork features.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e2. Platform Gate Bypass\u003c/strong\u003e\u003c/summary\u003e\n\nThe platform-gate function (minified name changes per build — `xPt()` in v1.1.3963, `wj()` in older builds) checks if Cowork is supported. `enable-cowork.py` finds it automatically and replaces it to unconditionally return `{status: \"supported\"}`.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e3. Swift Addon Stub\u003c/strong\u003e\u003c/summary\u003e\n\nThe original `@ant/claude-swift` uses Apple's Virtualization Framework. Our stub:\n\n- Implements the same API surface\n- Delegates spawn logic to `session_orchestrator.js` for proper lifecycle management\n- Line-buffers JSON output for proper stream parsing\n- Translates VM paths to host paths\n\nKey insight: The app calls `Si()` which returns `module.default.vm`, so methods must be on the `vm` object.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e4. Native Utilities Stub\u003c/strong\u003e\u003c/summary\u003e\n\nThe app also expects `@ant/claude-native` (a macOS-specific native module). Our stub provides minimal compatibility so the app can start on Linux. For example, OAuth flows fall back to opening the system browser via `xdg-open`.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e5. Session Orchestration Layer\u003c/strong\u003e\u003c/summary\u003e\n\nThe `stubs/cowork/` orchestration layer provides 15 modules that handle session lifecycle, IPC communication, transcript persistence, and security:\n\n- **session_orchestrator.js** coordinates all spawn operations, mount symlinks, and process cleanup\n- **credential_classifier.js** prevents auth token leakage to spawned processes\n- **ipc_tap.js** discovers EIPC channels at runtime by tapping `ipcMain._invokeHandlers.set()`\n- **transcript_store.js** persists conversation history to `~/.config/Claude/local-agent-mode-sessions/`\n- **file_watch_manager.js** detects file changes in the working directory\n\nAll modules follow XDG Base Directory conventions and are tested with 215+ test cases.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e6. Direct Execution\u003c/strong\u003e\u003c/summary\u003e\n\nOn macOS, Cowork runs a Linux VM. On Linux, we skip the VM entirely and run the Claude Code binary directly on the host. This is actually simpler and faster!\n\nThe stub resolves the binary in priority order:\n```\n$CLAUDE_CODE_PATH                                    (explicit override)\n~/.config/Claude/claude-code-vm/{version}/claude    (downloaded by Desktop)\n~/.local/bin/claude                                  (npm/bun global)\n~/.npm-global/bin/claude\n/usr/local/bin/claude\n/usr/bin/claude\n/home/linuxbrew/.linuxbrew/bin/claude               (Linuxbrew system)\n~/.linuxbrew/bin/claude                              (Linuxbrew user)\n~/.local/share/mise/shims/claude                     (mise version manager)\n~/.asdf/shims/claude                                 (asdf version manager)\n```\n\n**Code tab binary fixup**: `launch.sh` automatically detects if the Claude Code binary in the asar is a macOS Mach-O binary and replaces it with a symlink to the host Linux binary. This enables the Code tab to work seamlessly.\n\n\u003c/details\u003e\n\n---\n\n## ![](.github/assets/icons/folder-24x24.png) Project Structure\n\n```\nclaude-cowork-linux/\n├── stubs/\n│   ├── @ant/claude-swift/js/index.js   # Primary stub: vm.spawn() → delegates to orchestrator\n│   ├── @ant/claude-native/index.js     # Auth (xdg-open), keyboard constants, platform helpers\n│   ├── cowork/                         # Orchestration layer (15 modules)\n│   │   ├── session_orchestrator.js     # Spawn lifecycle coordinator\n│   │   ├── asar_adapter.js             # Asar IPC API compatibility\n│   │   ├── process_manager.js          # Process lifecycle \u0026 I/O\n│   │   ├── resume_coordinator.js       # Session resume logic\n│   │   ├── sessions_api.js             # Session CRUD operations\n│   │   ├── session_store.js            # In-memory session state\n│   │   ├── transcript_store.js         # Transcript persistence\n│   │   ├── file_registry.js            # Working directory tracking\n│   │   ├── file_watch_manager.js       # File change detection\n│   │   ├── stream_protocol.js          # JSON-RPC stream parsing\n│   │   ├── credential_classifier.js    # Token leak prevention\n│   │   ├── eipc_channel.js             # EIPC message protocol\n│   │   ├── ipc_tap.js                  # IPC channel discovery\n│   │   ├── dirs.js                     # XDG directory resolution\n│   │   └── file_identity.js            # Path normalization\n│   └── frame-fix/\n│       ├── frame-fix-wrapper.js        # Early bootstrap: TMPDIR fix, platform spoofing, graceful shutdown\n│       └── frame-fix-entry.js          # Entry point: loads frame-fix-wrapper then main index.js\n├── tests/\n│   ├── node/current-path/             # 18 test files, 215+ node:test cases\n│   │   ├── asar_adapter.test.cjs\n│   │   ├── credential_classifier.test.cjs\n│   │   ├── dirs.test.cjs\n│   │   ├── eipc_channel.test.cjs\n│   │   ├── file_identity.test.cjs\n│   │   ├── file_registry.test.cjs\n│   │   ├── file_watch_manager.test.cjs\n│   │   ├── ipc_tap.test.cjs\n│   │   ├── process_manager.test.cjs\n│   │   ├── resume_coordinator.test.cjs\n│   │   ├── session_orchestrator.test.cjs\n│   │   ├── session_store.test.cjs\n│   │   ├── sessions_api.test.cjs\n│   │   ├── stream_protocol.test.cjs\n│   │   ├── transcript_store.test.cjs\n│   │   └── ... (integration tests)\n│   ├── test-install-paths.sh          # 8-stage install validation (static analysis → Docker)\n│   └── Dockerfile.test                # Arch Linux container for full install testing\n├── scripts/\n│   ├── fetch-dmg.js                   # Auto-download Claude DMG via Node.js fetch\n│   └── enable-cowork.py               # Patches platform gate to return {status:\"supported\"}\n├── docs/\n│   ├── FAQ.md                         # Detailed troubleshooting guide\n│   ├── extensions.md                  # MCP and Chrome Extension integration overview\n│   ├── known-issues.md                # Safe Storage encryption, keyring setup\n│   └── safestorage-tokens.md          # How to persist tokens across restarts\n├── config/\n│   └── hyprland/claude.conf           # Optional: Hyprland window rules\n├── .github/assets/                    # README icons and hero image\n├── install.sh                         # Installer + --doctor preflight diagnostics\n├── launch.sh                          # Launcher: syncs stubs, repacks asar, runs electron\n├── launch-devtools.sh                 # Launcher with --inspect (Node.js DevTools)\n├── validate.sh                        # Env var checks, stub URL validation, log scanning\n├── PKGBUILD                           # Arch Linux AUR package definition\n├── docs/releases/                     # Per-version release notes\n├── docs/OAUTH-COMPLIANCE.md           # OAuth token handling audit\n├── CLAUDE.md                          # Project guide and critical paths\n├── README.md                          # This file\n└── LICENSE\n```\n\nAfter running `install.sh`, the `linux-app-extracted/` directory will contain the extracted Claude Desktop.\n\n---\n\n## ![](.github/assets/icons/console-24x24.png) Manual Setup\n\nIf the automated installer doesn't work, follow these steps:\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e1. Extract Claude Desktop from DMG\u003c/strong\u003e\u003c/summary\u003e\n\nThe installer handles `app.asar` extraction automatically. For manual extraction or older unpacked versions:\n\n```bash\n# Extract DMG with 7z\n7z x Claude-*.dmg -o/tmp/claude-extract\n\n# Create app directory\nmkdir -p linux-app-extracted\n\n# For newer versions (app.asar):\nif [ -f \"/tmp/claude-extract/Claude/Claude.app/Contents/Resources/app.asar\" ]; then\n    npx --yes asar extract \"/tmp/claude-extract/Claude/Claude.app/Contents/Resources/app.asar\" linux-app-extracted\n    # Copy unpacked files if they exist\n    [ -d \"/tmp/claude-extract/Claude/Claude.app/Contents/Resources/app.asar.unpacked\" ] \u0026\u0026 \\\n        cp -r \"/tmp/claude-extract/Claude/Claude.app/Contents/Resources/app.asar.unpacked/\"* linux-app-extracted/\n# For older versions (unpacked app/):\nelif [ -d \"/tmp/claude-extract/Claude/Claude.app/Contents/Resources/app\" ]; then\n    cp -r \"/tmp/claude-extract/Claude/Claude.app/Contents/Resources/app/\"* linux-app-extracted/\nfi\n\n# Cleanup\nrm -rf /tmp/claude-extract\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e2. Install Stub Modules\u003c/strong\u003e\u003c/summary\u003e\n\n```bash\n# Copy our stubs over the original modules\ncp -r stubs/@ant/* linux-app-extracted/node_modules/@ant/\ncp -r stubs/cowork linux-app-extracted/node_modules/\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e3. Patch index.js\u003c/strong\u003e\u003c/summary\u003e\n\nRun the cowork patch (auto-detects the minified function name):\n\n```bash\npython3 scripts/enable-cowork.py linux-app-extracted/.vite/build/index.js\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e4. Create Required Directories\u003c/strong\u003e\u003c/summary\u003e\n\n```bash\n# Create user session directory\nmkdir -p \"$HOME/.config/Claude/local-agent-mode-sessions/sessions\"\nchmod 700 \"$HOME/.config/Claude/local-agent-mode-sessions/sessions\"\n\n# Create symlink (requires sudo once)\nsudo ln -s \"$HOME/.config/Claude/local-agent-mode-sessions/sessions\" /sessions\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e5. Install Electron and asar\u003c/strong\u003e\u003c/summary\u003e\n\n```bash\n# System package (preferred)\n# Arch: pacman -S electron\n# Ubuntu/Debian: apt install electron\n# Or via npm:\nnpm install -g electron @electron/asar\n```\n\n\u003c/details\u003e\n\n---\n\n## ![](.github/assets/icons/warning-24x24.png) Troubleshooting\n\nFor detailed troubleshooting guides, see **[docs/FAQ.md](docs/FAQ.md)**.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eVerify patches were applied\u003c/strong\u003e\u003c/summary\u003e\n\nCheck that the Cowork patch is present in `linux-app-extracted/.vite/build/index.js`:\n\n```bash\ngrep -q 'cowork-patched' linux-app-extracted/.vite/build/index.js \u0026\u0026 echo \"✓ Cowork patch applied\" || echo \"✗ Patch missing - run ./install.sh\"\n```\n\nThe patch replaces the platform-gate function to return `{status:\"supported\"}` unconditionally, enabling Cowork on Linux. The `/*cowork-patched*/` marker indicates successful patching.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eEACCES: permission denied, mkdir '/sessions'\u003c/strong\u003e\u003c/summary\u003e\n\nCreate a symlink to user space instead of a world-writable directory:\n\n```bash\nmkdir -p \"$HOME/.config/Claude/local-agent-mode-sessions/sessions\"\nsudo ln -s \"$HOME/.config/Claude/local-agent-mode-sessions/sessions\" /sessions\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eUnexpected non-whitespace character after JSON\u003c/strong\u003e\u003c/summary\u003e\n\nJSON parsing issue. The stub uses line buffering to send complete JSON objects. If this persists, check the trace log:\n\n```bash\ncat ~/.local/state/claude-cowork/logs/claude-swift-trace.log\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eFailed to start Claude's workspace\u003c/strong\u003e\u003c/summary\u003e\n\nRun `claude-desktop --doctor` first to check your environment. Then verify:\n\n1. The swift stub is properly loaded (check for `[claude-swift-stub] LOADING MODULE` in logs)\n2. The Claude binary exists at one of the resolved paths (`~/.local/bin/claude`, `~/.config/Claude/claude-code-vm/{version}/claude`, etc.)\n3. You have a valid Claude account\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eProcess exits immediately (code=1)\u003c/strong\u003e\u003c/summary\u003e\n\nCheck stderr in the trace log for the actual error:\n\n```bash\ntail -50 ~/.local/state/claude-cowork/logs/claude-swift-trace.log\n```\n\nCommon issues:\n- Missing `/sessions` symlink\n- Binary not found\n- Permission issues\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003et.setEventCallbacks is not a function\u003c/strong\u003e\u003c/summary\u003e\n\nThis means the stub isn't exporting methods correctly. The app expects:\n- `module.default.vm.setEventCallbacks()` — NOT on the class directly\n\nEnsure the stub has methods on the `this.vm` object, not just the class.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eApp won't relaunch / appears to do nothing\u003c/strong\u003e\u003c/summary\u003e\n\nA previous instance may not have shut down cleanly, leaving a stale lock file. Clear it and relaunch:\n\n```bash\nrm -f ~/.config/Claude/SingletonLock ~/.config/Claude/SingletonSocket ~/.config/Claude/SingletonCookie\nclaude-desktop\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eGlobal shortcuts don't work on Wayland (GNOME)\u003c/strong\u003e\u003c/summary\u003e\n\nThe app enables `GlobalShortcutsPortal` for Wayland global shortcut support via `xdg-desktop-portal`. This works on **KDE Plasma** and **Hyprland** but **not on GNOME** — `xdg-desktop-portal-gnome` has not implemented the GlobalShortcuts portal yet.\n\n**Workaround for GNOME Wayland users:** Set a custom shortcut in GNOME Settings \u003e Keyboard \u003e Custom Shortcuts to launch `claude-desktop`.\n\n\u003c/details\u003e\n\n---\n\n## ![](.github/assets/icons/console-24x24.png) Development\n\n```bash\n./launch.sh                   # repacks asar automatically if stubs changed\n./launch-devtools.sh          # with Node.js inspector\n./validate.sh                 # env var checks, stub URL validation, log errors\n./install.sh --doctor         # preflight: binaries, node, CLI, /sessions, secret service, patches\n\n# Run tests\nnode --test tests/node/current-path/*.test.cjs\n```\n\n### Debug Logging\n\n```bash\n# Include Claude Code stdout/stderr in the trace log (redacted, but still treat logs as sensitive)\nexport CLAUDE_COWORK_TRACE_IO=1\n\n# Enable debug mode\nexport CLAUDE_COWORK_DEBUG=1\n\n# Enable Electron logging\nexport ELECTRON_ENABLE_LOGGING=1\n\n# Clear old logs\nrm -f ~/.local/state/claude-cowork/logs/claude-swift-trace.log\n\n# Run with output capture\n./launch.sh 2\u003e\u00261 | tee /tmp/claude-full.log\n\n# In another terminal, watch the trace\ntail -f ~/.local/state/claude-cowork/logs/claude-swift-trace.log\n```\n\n### Trace Log Format\n\nThe stub writes to `~/.local/state/claude-cowork/logs/claude-swift-trace.log`:\n\n```\n[timestamp] === MODULE LOADING ===\n[timestamp] vm.setEventCallbacks() CALLED\n[timestamp] vm.startVM() bundlePath=... memoryGB=4\n[timestamp] vm.spawn() id=... cmd=... args=[...]\n[timestamp] Translated command: /usr/local/bin/claude -\u003e ~/.config/Claude/...\n[timestamp] stdout line: {\"type\":\"stream_event\",...}\n[timestamp] Process ... exited: code=0\n```\n\n---\n\n## ![](.github/assets/icons/shield-security-protection-24x24.png) Security\n\nThis project includes security hardening:\n\n- **Command allowlist** - Only vetted binary paths are accepted by `vm.spawn()`; unknown commands are rejected\n- **Command injection prevention** - Uses `execFile()` instead of `exec()`\n- **Path traversal protection** - Validates session paths with `isPathSafe()`\n- **Environment filtering** - Allowlist of safe environment variables\n- **Secure permissions** - Session directory uses 700, not 777\n- **Symlink for /sessions** - No world-writable directories\n- **URL origin validation** - `Auth_$_doAuthInBrowser` and `AuthRequest.start()` enforce Anthropic-only domains\n- **OAuth compliance** - `BLOCKED_ENV_KEY_PATTERN` + `CREDENTIAL_EXEMPT_KEYS` prevent token leakage to subprocesses\n- **Credential classification** - `credential_classifier.js` enforces strict token leak prevention with allowlist-based exemptions\n- **CRLF guards** - Stream parsers reject CRLF injection attempts in JSON-RPC messages\n- **FD bounds checking** - File descriptor limits enforced on spawned processes to prevent resource exhaustion\n\n---\n\n## Legal Notice\n\n\u003e [!CAUTION]\n\u003e This project is for **educational and research purposes**. Claude Desktop is proprietary software owned by Anthropic PBC. Use of Cowork requires a valid Claude account.\n\u003e\n\u003e This repository contains only stub implementations and patches—**not** the Claude Desktop application itself. You must obtain Claude Desktop directly from Anthropic.\n\u003e\n\u003e This project is **not affiliated with, endorsed by, or sponsored by** Anthropic. \"Claude\" is a trademark of Anthropic PBC.\n\n---\n\n## Credits\n\nReverse engineered and implemented by examining the Claude Desktop Electron app structure, binary analysis with pyghidra-lite, and iterative debugging.\n\n**Contributors:**\n- [@Boermt-die-Buse](https://github.com/Boermt-die-Buse) -- Linux UI fixes: native window frames, titlebar patch, icon extraction\n- [@JaPossert](https://github.com/JaPossert) -- Resources copy fix, Wayland global shortcuts report\n- [@alpham8](https://github.com/alpham8) -- openSUSE compatibility fixes, binary resolution paths, Swift stub method stubs\n- [@matiasandina](https://github.com/matiasandina) -- icon fix and terminal detach proposals (issue #37)\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\n**MIT License** · See [LICENSE](LICENSE) for details\n\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohnzfitch%2Fclaude-cowork-linux","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjohnzfitch%2Fclaude-cowork-linux","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohnzfitch%2Fclaude-cowork-linux/lists"}