This document provides comprehensive information about building Claude Code as single-binary executables for multiple platforms using Bun's native compilation and embedding features.
- Overview
- Technical Architecture
- Build Prerequisites
- Building Executables
- Distribution Matrix
- Platform-Specific Notes
- Troubleshooting
- Windows-Specific Fixes
- Technical Details
- Contributing
- License
Claude Code can be compiled into standalone executables that bundle the entire application, runtime, and all assets into a single binary file. This eliminates the need for users to install Node.js, Bun, or any dependencies.
The source package is fetched from the official npm registry: @anthropic-ai/claude-code
- Zero Dependencies: Single executable file with no external requirements
- Cross-Platform: Build for Linux, macOS, and Windows from any platform
- Optimized: Includes minification, sourcemaps, and optional bytecode compilation
- Embedded Assets: All resources (WASM files, native modules) are embedded directly
- Multiple Variants: Support for modern CPUs, older hardware, and different libc implementations
graph TD
A[Original CLI Source] --> B[prepare-bundle-native.js]
B --> C[Modified CLI with Embedded Assets]
C --> D[Bun Build --compile]
D --> E[Single Binary Executable]
F[yoga.wasm] --> B
G[ripgrep binaries] --> B
H[Other assets] --> B
The build process uses Bun's native file embedding feature (import ... with { type: "file" }
):
- Asset Discovery: Identifies all external files (yoga.wasm, ripgrep binaries)
- Import Injection: Adds import statements for each asset at the top of the CLI
- Path Patching: Modifies file loading code to use embedded assets instead of filesystem
- Compilation: Bun bundles everything into a single executable
- Bun v1.2.0 or later
- Git (for cloning the repository) or npm (for downloading the package)
- Disk Space: ~5GB for building all targets
Claude Code is published on npm as @anthropic-ai/claude-code
. To download and extract it locally:
# Download the tarball from npm
npm pack @anthropic-ai/claude-code
# Extract it
tar -xzf anthropic-ai-claude-code-*.tgz
# The sources will be in the 'package' directory
cd package
# Install Bun (if not already installed)
curl -fsSL https://bun.sh/install | bash
# Install dependencies (if any)
bun install
# Build for current platform only
bun run scripts/build/build-executables.js current
# Build all platforms
bun run scripts/build/build-executables.js all
# Build specific platform family
bun run scripts/build/build-executables.js linux # All Linux variants
bun run scripts/build/build-executables.js macos # All macOS variants
bun run scripts/build/build-executables.js windows # All Windows variants
Prepares the CLI source for bundling by:
- Embedding yoga.wasm as base64 or native import
- Adding embedded file mappings for ripgrep binaries
- Modifying file loading paths to use embedded resources
Main build orchestrator that:
- Runs the preparation script
- Executes Bun build with appropriate flags
- Handles multiple targets sequentially
- Cleans up temporary files
All executables are built with these optimizations:
Flag | Purpose | Impact |
---|---|---|
--compile |
Create standalone executable | Bundles Bun runtime |
--minify |
Minimize code size | Reduces file size by ~30% |
--sourcemap |
Embed source maps | Enables debugging with original source |
--bytecode |
Precompile to bytecode | Faster startup (experimental) |
File Name | Platform | Architecture | CPU Requirements | C Library | Size | Notes |
---|---|---|---|---|---|---|
Linux - Standard (glibc) | ||||||
claude-code-linux-x64 |
Linux | x64 | Any x64 CPU | glibc | 266MB | Default Linux build |
claude-code-linux-x64-modern |
Linux | x64 | AVX2 (2013+) | glibc | 266MB | Optimized for modern CPUs |
claude-code-linux-x64-baseline |
Linux | x64 | SSE2 (2003+) | glibc | 265MB | Compatible with older CPUs |
claude-code-linux-arm64 |
Linux | ARM64 | ARMv8 | glibc | 259MB | For ARM servers, Raspberry Pi 4+ |
Linux - Alpine (musl) | ||||||
claude-code-linux-x64-musl |
Linux | x64 | Any x64 CPU | musl | 245MB | For Alpine Linux |
claude-code-linux-x64-musl-modern |
Linux | x64 | AVX2 (2013+) | musl | 245MB | Alpine + modern CPU |
claude-code-linux-x64-musl-baseline |
Linux | x64 | SSE2 (2003+) | musl | 245MB | Alpine + older CPU |
claude-code-linux-arm64-musl |
Linux | ARM64 | ARMv8 | musl | 240MB | Alpine on ARM |
macOS | ||||||
claude-code-macos-x64 |
macOS | x64 | Any Intel Mac | - | 228MB | Intel Macs |
claude-code-macos-x64-modern |
macOS | x64 | AVX2 (2013+) | - | 228MB | Newer Intel Macs |
claude-code-macos-x64-baseline |
macOS | x64 | SSE2 (2006+) | - | 228MB | Older Intel Macs |
claude-code-macos-arm64 |
macOS | ARM64 | Apple Silicon | - | 224MB | M1/M2/M3 Macs |
Windows | ||||||
claude-code-windows-x64.exe |
Windows | x64 | Any x64 CPU | - | 280MB | Standard Windows build |
claude-code-windows-x64-modern.exe |
Windows | x64 | AVX2 (2013+) | - | 280MB | Modern Windows PCs |
claude-code-windows-x64-baseline.exe |
Windows | x64 | SSE2 (2003+) | - | 280MB | Older Windows PCs |
If you need... | Choose... |
---|---|
Maximum compatibility | *-baseline variants |
Best performance | *-modern variants |
Docker/Alpine Linux | *-musl variants |
Not sure | Default variants (no suffix) |
# Linux - Check CPU features
lscpu | grep -i avx2 # If present, use -modern
# Check libc type
ldd --version # GNU libc = standard, musl = use -musl
# macOS - Check architecture
uname -m # arm64 = Apple Silicon, x86_64 = Intel
- Modern: Requires AVX2 instruction set (Intel Haswell 2013+, AMD Excavator 2015+)
- Baseline: Requires only SSE2 (Intel Pentium 4 2000+, AMD Athlon 64 2003+)
- Default: Auto-detects at runtime (safe choice)
- glibc (standard): Ubuntu, Debian, RHEL, Fedora, most distros
- musl: Alpine Linux, void Linux, minimal containers
# If you see "Illegal instruction" error:
# 1. Try the -baseline variant
# 2. Check CPU features:
cat /proc/cpuinfo | grep flags
Currently, we build separate binaries for Intel and Apple Silicon. To create a universal binary:
# Combine Intel and ARM64 (requires macOS)
lipo -create claude-code-macos-x64 claude-code-macos-arm64 \
-output claude-code-macos-universal
Executables may need to be signed for distribution:
# Sign the executable
codesign --force --deep --sign "Developer ID Application: Your Name" claude-code-macos-arm64
# Verify signature
codesign -vvv --verify claude-code-macos-arm64
Windows may show security warnings for unsigned executables. Users can:
- Click "More info" → "Run anyway"
- Or sign the executable with a code signing certificate
Some antivirus software may flag the executable. This is common for:
- Packed/bundled executables
- Unsigned binaries
- Files downloaded from the internet
Issue | Solution |
---|---|
"Cannot find module './yoga.wasm'" | Embedded assets failed to load. Rebuild with latest scripts |
"Illegal instruction" | Use -baseline variant for older CPUs |
"GLIBC_2.XX not found" | Use -musl variant or build on older system |
Large file size | Normal - includes full runtime and embedded assets |
Slow startup | Try building without --bytecode flag |
Enable debug output:
DEBUG=1 ./claude-code-linux-x64 --help
Verify executable integrity:
# Check file type
file claude-code-linux-x64
# Check dependencies (should be minimal)
ldd claude-code-linux-x64 # Linux
otool -L claude-code-macos-arm64 # macOS
# Test basic functionality
./claude-code-linux-x64 --version
./claude-code-linux-x64 --print "Hello"
Windows executables were failing with the error:
SyntaxError: import.meta is only valid inside modules.
And later, after initial fixes:
TypeError: File URL path must be an absolute path
This occurred because Bun wraps ES module code in a CommonJS-style function when compiling Windows executables:
(function(exports, require, module, __filename, __dirname) {
// ... ES module code here
})
Since import.meta
is an ES module feature that's not valid inside CommonJS contexts, and the codebase uses import.meta.url
in multiple places, Windows builds would fail immediately.
A Windows-specific build preparation script (scripts/build/prepare-windows-bundle.js
) was created that applies a two-layer patching approach:
- Embeds yoga.wasm file using Bun's native file embedding
- Embeds ripgrep binaries for all platforms
- Handles ripgrep path resolution for embedded files
- Bypasses POSIX shell requirement
- Sets up all embedded file handling
-
Ensures absolute paths for file URLs to prevent "File URL path must be an absolute path" errors:
// Ensure we have an absolute path for __filename let __executablePath; if (process.argv[1]) { const path = require('path'); __executablePath = path.isAbsolute(process.argv[1]) ? process.argv[1] : path.resolve(process.argv[1]); } else { // Fallback to current working directory + a dummy filename __executablePath = require('path').join(process.cwd(), 'claude-code.exe'); }
-
Creates a helper function for proper file URL generation:
function __toFileURL(path) { const resolved = require('path').resolve(path); // On Windows, we need to handle drive letters properly if (process.platform === 'win32') { // Convert backslashes to forward slashes and ensure proper format return 'file:///' + resolved.replace(/\\/g, '/'); } return 'file://' + resolved; }
-
Replaces all
import.meta.url
references with the helper function:// Before: import.meta.url // After: __toFileURL(__filename)
-
Handles
fileURLToPath(import.meta.url)
patterns simply:// Before: fileURLToPath(import.meta.url) // After: __filename
-
Places compatibility code at the right location - immediately after the shebang to ensure functions are defined before use
-
Both patch layers are required: Windows builds need ALL the native bundle preparations PLUS the import.meta fixes. The initial error was caused by replacing native preparations instead of building on top of them.
-
File URL validity: The key issue was that
process.argv[1]
in Windows executables can be:- A relative path (e.g.,
.\claude-code.exe
) - Just a filename (e.g.,
claude-code.exe
) - Undefined in some cases
- Or even just
.
This would create invalid file URLs like
file://./claude-code.exe
orfile:///
. - A relative path (e.g.,
-
Proper file URL format: Windows absolute paths require three slashes (
file:///C:/path
) while Unix paths use two (file:///path
).
The main build script automatically uses the Windows-specific preparation for Windows targets:
- Separates Windows and non-Windows builds
- First runs standard native bundle preparations
- Then applies Windows-specific import.meta fixes on top
- Cleans up temporary build directories after completion
The fix ensures that:
- Windows executables compile without import.meta errors
- File URLs are always valid regardless of how the executable is invoked
- All functionality is preserved including embedded assets
- All Windows variants (baseline, modern, standard) work correctly
Claude Code previously required a POSIX-compliant shell (like Git Bash, WSL, MSYS2, or Cygwin) to run on Windows. Without one of these shells installed, users would get the error:
No suitable shell found. Claude CLI requires a Posix shell environment. Please ensure you have a valid shell installed and the SHELL environment variable set.
The POSIX shell requirement has been completely bypassed in the bundled executables. The patch modifies the shell validation logic to:
- Still attempt to find a suitable shell using the original logic
- If no shell is found, instead of throwing an error, it automatically assigns:
cmd.exe
on Windows/bin/sh
on Unix-like systems
In scripts/build/prepare-bundle-native.js
, a patch was added that replaces:
let J=W.find((F)=>F&&cw0(F));
if(!J){
let F="No suitable shell found. Claude CLI requires a Posix shell environment...";
throw h1(new Error(F)),new Error(F)
}
With:
let J=W.find((F)=>F&&cw0(F));
if(!J){
J=process.platform==="win32"?"cmd.exe":"/bin/sh"
}
- No Dependencies: Windows users no longer need to install Git Bash, WSL, or any POSIX shell
- Works Out-of-the-Box: Claude Code executables now run on ANY Windows system
- Backwards Compatible: If a POSIX shell IS available, it will still be used
- Cross-Platform: The bypass works on all platforms, not just Windows
Two test scripts are provided in scripts/test/
:
Batch Script:
scripts\test\test-shell-bypass.bat
PowerShell Script:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
.\scripts\test\test-shell-bypass.ps1
These scripts:
- Clear the SHELL environment variable
- Test all Windows executable variants
- Verify they work without any POSIX shell installed
- This bypass only applies to bundled executables, not the source code version
- Commands are now translated from POSIX to Windows syntax when using
cmd.exe
:- Single quotes → Double quotes
/dev/null
→NUL
source
commands → Commented outeval
→ Direct executionpwd -P
→cd
(current directory)
- The bypass ensures basic functionality works on all systems
- Advanced users can still set the SHELL environment variable to use their preferred shell
Problem: Top-level await
in the yoga.wasm loading code caused bytecode compilation failures.
Solution: Wrapped the async operation in an IIFE to ensure proper async context.
Problem: undefined is not an object (evaluating '$.includes')
error when running rg --version
on Windows ARM64 emulation.
Root Cause: Template literal syntax with escaped backticks in minified code was causing issues with variable interpolation.
Solution:
- Replaced template literals with string concatenation
- Added defensive checks for undefined values
- Created a safe platform detection helper function
- Added try-catch blocks with proper error handling
Problem: Even with the POSIX shell bypass, ripgrep commands would fail with errors like:
'laude-f60c-cwd"' is not recognized as an internal or external command
Root Cause: The command builder was generating POSIX shell syntax (single quotes, /dev/null
, source
, eval
, etc.) but passing it to cmd.exe
, which doesn't understand these constructs.
Solution: Added Windows command translation in scripts/build/prepare-windows-bundle.js
:
- Convert
/dev/null
→NUL
(Windows null device) - Convert
source ${Y}
→REM source ${Y}
(comment out) - Convert
eval ${F}
→${F}
(direct execution) - Convert
pwd -P >| ${J}
→cd > ${J}
(current directory) - Override
shell-quote
to use Windows double-quote escaping instead of single quotes - Leave shell metacharacters (
<
,>
,|
,&&
) unquoted for cmd.exe
In scripts/build/prepare-bundle-native.js
:
- Added
__getSafePlatform()
helper function for safe platform detection - Replaced template literals with string concatenation
- Added defensive checks for
process
,process.arch
, andprocess.platform
- Added proper error handling with try-catch blocks
- Added checks for
__embeddedFiles
existence before accessing
In scripts/build/prepare-windows-bundle.js
:
- Added Windows shell command translation layer
- Overrode
shell-quote
module to produce cmd.exe-compatible quoting - Converted POSIX shell constructs to Windows equivalents
Two test scripts are provided in scripts/test/
:
Batch Script:
scripts\test\test-ripgrep-windows.bat
PowerShell Script:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
.\scripts\test\test-ripgrep-windows.ps1
After the fixes, running Bash(rg --version)
should output:
ripgrep X.X.X
And searching with Bash(rg "hello" "C:\Users\Rob Banks\Downloads")
now works correctly without requiring a POSIX shell.
- The bytecode compilation still fails for complex bundled code, but this is expected
- The executables are built successfully without bytecode
- All Windows variants (standard, baseline, modern) should now work correctly
- The fix ensures compatibility with Windows ARM64 x64 emulation environments
- Ripgrep now works with plain
cmd.exe
without requiring Git Bash or WSL
Your Windows 11 ARM64 system should be able to run x64 binaries through emulation, but the Claude Code executable may fail silently. Here's how to diagnose and potentially fix the issue.
-
Copy the debug scripts to your Windows VM:
scripts/debug/debug-windows-arm64.bat
scripts/debug/debug-arm64.ps1
-
Run the batch file first:
cd C:\path\to\your\dist ..\scripts\debug\debug-windows-arm64.bat
-
Run the PowerShell script for more details:
cd C:\path\to\your\dist Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass ..\scripts\debug\debug-arm64.ps1
Windows 11 ARM64 should have x64 emulation enabled by default, but sometimes it needs configuration.
Check if x64 emulation is enabled:
- Open Registry Editor (regedit)
- Navigate to:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
- Look for any entries that might disable x64 emulation
The Bun runtime might need Visual C++ redistributables that aren't included in the ARM64 emulation layer.
Install both ARM64 and x64 versions:
- Download from Microsoft:
- Install both versions
The ripgrep.node native module might not work under x64 emulation.
Test without ripgrep: Create a simple test to see if it's the native modules causing issues:
# Set environment variable to disable ripgrep
$env:DISABLE_RIPGREP = "1"
.\claude-code-windows-x64.exe --help
Bun's runtime might have specific issues with Windows ARM64 x64 emulation.
Alternative approaches:
-
Use Wine in WSL2 (if UTM supports nested virtualization):
# In WSL2 on your Windows ARM64 VM sudo apt update sudo apt install wine64 wine64 claude-code-windows-x64.exe --help
-
Build from source (requires Node.js):
# Install Node.js for ARM64 Windows first npm install -g @anthropic-ai/claude-code claude --help
Run these in PowerShell to gather more info:
# Check x64 emulation status
Get-AppxPackage | Where-Object {$_.Name -like "*x64*"}
# Check Windows version and features
winver
Get-WindowsOptionalFeature -Online | Where-Object {$_.FeatureName -like "*Hyper*" -or $_.FeatureName -like "*x64*"}
# Check for crash dumps
Get-ChildItem "$env:LOCALAPPDATA\CrashDumps" -Filter "claude-code*.dmp" -ErrorAction SilentlyContinue
# Test a simple x64 binary (download any small x64 tool to test)
# This helps determine if it's a general x64 emulation issue or Bun-specific
Since neither Bun nor ripgrep provide native Windows ARM64 binaries, your options are limited:
- Use the macOS or Linux version in UTM instead of Windows
- Wait for native support - Monitor:
- Use an x64 Windows VM instead of ARM64 (will be slower due to full CPU emulation)
After running the diagnostic scripts, please share:
- The output from both scripts
- Any error messages from Event Viewer
- Whether other x64 programs work on your system
This will help determine if it's a Bun-specific issue or a general x64 emulation problem.
The following assets are embedded directly into each executable:
Asset | Purpose | Size |
---|---|---|
yoga.wasm |
Layout engine for terminal UI | 87KB |
ripgrep binaries |
Fast file searching | ~2MB per platform |
vsix extension |
VS Code integration | Variable |
The build process modifies these loading mechanisms:
-
WebAssembly Loading
// Original await readFile("./yoga.wasm") // Modified await Bun.file(__embeddedYogaWasm).arrayBuffer()
-
Native Module Loading
// Original require("./vendor/ripgrep/x64-linux/ripgrep.node") // Modified require(__embeddedFiles["vendor/ripgrep/x64-linux/ripgrep.node"])
Typical build times on Apple M1:
- Single target: 15-30 seconds
- All targets: 2-5 minutes
- With bytecode: +20% build time
- Supply Chain: All embedded binaries are from verified sources
- Reproducible Builds: Build process is deterministic
- No Runtime Downloads: Everything is self-contained
- Code Signing: Binaries can be signed post-build
To add support for new platforms:
- Check Bun's supported targets:
bun build --compile --help
- Add target configuration to
PLATFORMS
inscripts/build/build-executables.js
- Test the build thoroughly
- Update this documentation
Current areas for optimization:
- Reduce binary size (currently 200-300MB)
- Implement proper bytecode compilation when stable
- Add automatic code signing
- Create GitHub Actions for automated builds
See the main LICENSE file in the repository root.
Generated executables include the Bun runtime, which is licensed under MIT.