Based on the original installation method from: https://code.claude.com/docs/en/setup#standard-installation
This is a Python rewrite of the script at https://claude.ai/install.sh, but removing the claude install call at the end.
Based on the original installation method from: https://code.claude.com/docs/en/setup#standard-installation
This is a Python rewrite of the script at https://claude.ai/install.sh, but removing the claude install call at the end.
| #!/usr/bin/env python3 | |
| """Install Claude Code CLI.""" | |
| import argparse | |
| import hashlib | |
| import json | |
| import platform | |
| import re | |
| import subprocess | |
| import sys | |
| import urllib.request | |
| from pathlib import Path | |
| GCS_BUCKET = "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases" | |
| def parse_args() -> argparse.Namespace: | |
| parser = argparse.ArgumentParser(description="Install Claude Code CLI") | |
| parser.add_argument( | |
| "--target", | |
| type=str, | |
| default=None, | |
| help="Version target: stable, latest, or specific version (e.g., 1.2.3)", | |
| ) | |
| return parser.parse_args() | |
| def validate_target(target: str | None) -> None: | |
| if target is None: | |
| return | |
| pattern = r"^(stable|latest|[0-9]+\.[0-9]+\.[0-9]+(-[^\s]+)?)$" | |
| if not re.match(pattern, target): | |
| print(f"Invalid target: {target}", file=sys.stderr) | |
| print( | |
| "Usage: ,claude-install [--target stable|latest|VERSION]", file=sys.stderr | |
| ) | |
| sys.exit(1) | |
| def download(url: str) -> bytes: | |
| with urllib.request.urlopen(url, timeout=30) as resp: | |
| return resp.read() | |
| def download_to_file(url: str, path: Path) -> None: | |
| data = download(url) | |
| path.write_bytes(data) | |
| def detect_platform() -> str: | |
| system = platform.system() | |
| machine = platform.machine() | |
| if system == "Darwin": | |
| os_name = "darwin" | |
| elif system == "Linux": | |
| os_name = "linux" | |
| else: | |
| print(f"Unsupported OS: {system}", file=sys.stderr) | |
| sys.exit(1) | |
| if machine in ("x86_64", "amd64"): | |
| arch = "x64" | |
| elif machine in ("arm64", "aarch64"): | |
| arch = "arm64" | |
| else: | |
| print(f"Unsupported architecture: {machine}", file=sys.stderr) | |
| sys.exit(1) | |
| if os_name == "linux": | |
| is_musl = ( | |
| Path("/lib/libc.musl-x86_64.so.1").exists() | |
| or Path("/lib/libc.musl-aarch64.so.1").exists() | |
| or _check_musl_ldd() | |
| ) | |
| if is_musl: | |
| return f"linux-{arch}-musl" | |
| return f"linux-{arch}" | |
| return f"{os_name}-{arch}" | |
| def _check_musl_ldd() -> bool: | |
| try: | |
| result = subprocess.run( | |
| ["ldd", "/bin/ls"], | |
| capture_output=True, | |
| text=True, | |
| timeout=5, | |
| ) | |
| return "musl" in result.stdout or "musl" in result.stderr | |
| except Exception: | |
| return False | |
| def sha256_file(path: Path) -> str: | |
| h = hashlib.sha256() | |
| with open(path, "rb") as f: | |
| for chunk in iter(lambda: f.read(8192), b""): | |
| h.update(chunk) | |
| return h.hexdigest() | |
| def main(*, target: str | None) -> int: | |
| validate_target(target) | |
| plat = detect_platform() | |
| print("Fetching version info...") | |
| version = download(f"{GCS_BUCKET}/stable").decode().strip() | |
| print(f"Downloading manifest for version {version}...") | |
| manifest_data = download(f"{GCS_BUCKET}/{version}/manifest.json") | |
| manifest = json.loads(manifest_data) | |
| platform_info = manifest.get("platforms", {}).get(plat) | |
| if not platform_info: | |
| print(f"Platform {plat} not found in manifest", file=sys.stderr) | |
| return 1 | |
| checksum = platform_info.get("checksum", "") | |
| if not re.match(r"^[a-f0-9]{64}$", checksum): | |
| print("Invalid checksum in manifest", file=sys.stderr) | |
| return 1 | |
| binary_path = Path.cwd() / "claude" | |
| print(f"Downloading Claude Code for {plat}...") | |
| try: | |
| download_to_file(f"{GCS_BUCKET}/{version}/{plat}/claude", binary_path) | |
| except Exception as e: | |
| print(f"Download failed: {e}", file=sys.stderr) | |
| binary_path.unlink(missing_ok=True) | |
| return 1 | |
| print("Verifying checksum...") | |
| actual_checksum = sha256_file(binary_path) | |
| if actual_checksum != checksum: | |
| print("Checksum verification failed", file=sys.stderr) | |
| binary_path.unlink(missing_ok=True) | |
| return 1 | |
| # Make executable | |
| subprocess.run(["chmod", "+x", str(binary_path)], check=True) | |
| print() | |
| print("✅ Installation complete!") | |
| print() | |
| return 0 | |
| if __name__ == "__main__": | |
| args = parse_args() | |
| sys.exit(main(target=args.target)) |