#!/usr/bin/env python3 import argparse import json import os import sys from pathlib import Path DEFAULT_CLAUDE_JSON = Path.home() / ".claude.json" DEFAULT_SETTINGS_JSON = Path.home() / ".claude" / "settings.json" def load_json(path: Path) -> dict[str, object]: try: with open(path) as f: return dict(json.load(f)) except FileNotFoundError: return {} except json.JSONDecodeError as e: print(f"Error: Invalid JSON in {path}: {e}", file=sys.stderr) sys.exit(1) def save_json(path: Path, data: dict[str, object]) -> None: path.parent.mkdir(parents=True, exist_ok=True) with open(path, "w") as f: json.dump(data, f, indent=2) def main() -> None: parser = argparse.ArgumentParser( description="Initialize Claude configuration from environment variables" ) parser.add_argument( "--claude-json", type=Path, default=DEFAULT_CLAUDE_JSON, help="Path to .claude.json (default: ~/.claude.json)", ) parser.add_argument( "--settings-json", type=Path, default=DEFAULT_SETTINGS_JSON, help="Path to settings.json (default: ~/.claude/settings.json)", ) parser.add_argument( "--account-uuid", help="OAuth account UUID (or CLAUDE_ACCOUNT_UUID)", ) parser.add_argument( "--email", help="OAuth email address (or CLAUDE_EMAIL)", ) parser.add_argument( "--org-uuid", help="OAuth org UUID (or CLAUDE_ORG_UUID)", ) parser.add_argument( "--theme", choices=["dark", "light"], help="Color scheme (or CLAUDE_THEME)", ) parser.add_argument( "--skip-onboarding", action="store_true", help="Skip first-run dialogs (or CLAUDE_SKIP_ONBOARDING=1)", ) parser.add_argument( "--model", help="Default model identifier (or CLAUDE_MODEL)", ) parser.add_argument( "--effort", choices=["low", "medium", "high"], help="Effort level for supported models (or CLAUDE_EFFORT)", ) args = parser.parse_args() account_uuid = args.account_uuid or os.getenv("CLAUDE_ACCOUNT_UUID") email = args.email or os.getenv("CLAUDE_EMAIL") org_uuid = args.org_uuid or os.getenv("CLAUDE_ORG_UUID") theme = args.theme or os.getenv("CLAUDE_THEME") skip_onboarding = args.skip_onboarding or bool(os.getenv("CLAUDE_SKIP_ONBOARDING")) model = args.model or os.getenv("CLAUDE_MODEL") effort = args.effort or os.getenv("CLAUDE_EFFORT") if not any([account_uuid, email, org_uuid, theme, skip_onboarding, model, effort]): print("Warning: No configuration options provided", file=sys.stderr) sys.exit(0) claude_config = load_json(args.claude_json) settings_config = load_json(args.settings_json) if account_uuid or email or org_uuid: if "oauthAccount" not in claude_config: claude_config["oauthAccount"] = {} oauth = claude_config["oauthAccount"] assert isinstance(oauth, dict) if account_uuid: oauth["accountUuid"] = account_uuid if email: oauth["emailAddress"] = email if org_uuid: oauth["organizationUuid"] = org_uuid if skip_onboarding: claude_config.update( { "numStartups": 1, "installMethod": "native", "autoUpdates": False, "hasSeenTasksHint": True, "hasCompletedOnboarding": True, "hasSelectedColorScheme": True, } ) settings_config.update( { "hasCompletedSetup": True, "hasSelectedTheme": True, } ) if theme: settings_config["colorScheme"] = theme claude_config["hasSelectedColorScheme"] = True if model: settings_config["model"] = model if effort: settings_config["effortLevel"] = effort try: save_json(args.claude_json, claude_config) save_json(args.settings_json, settings_config) print(f"Updated {args.claude_json} and {args.settings_json}") except Exception as e: print(f"Error: {e}", file=sys.stderr) sys.exit(1) if __name__ == "__main__": main()