diff --git a/apps/backend/core/auth.py b/apps/backend/core/auth.py index 78faac550e..48ee0082a6 100644 --- a/apps/backend/core/auth.py +++ b/apps/backend/core/auth.py @@ -975,6 +975,13 @@ def get_sdk_env_vars() -> dict[str, str]: # The empty string ensures Python doesn't add any extra paths to sys.path. env["PYTHONPATH"] = "" + # Disable user's pre-commit hooks during Auto-Claude managed git operations + env["HUSKY"] = "0" + + # NOTE: Git environment variable isolation (GIT_INDEX_FILE, GIT_DIR, etc.) is handled + # in client.py by deleting these vars from os.environ before SDK instantiation. + # We cannot set them to "" here because git interprets empty string as a path value. + return env diff --git a/apps/backend/core/client.py b/apps/backend/core/client.py index de777f0624..038a1afa00 100644 --- a/apps/backend/core/client.py +++ b/apps/backend/core/client.py @@ -21,7 +21,12 @@ from pathlib import Path from typing import Any +<<<<<<< HEAD from core.fast_mode import ensure_fast_mode_in_user_settings +======= +# Git environment isolation - prevents worktree operation failures from inherited env vars +from core.git_executable import GIT_ENV_VARS_TO_CLEAR +>>>>>>> refs/remotes/upstream/pr/1599 from core.platform import ( is_windows, validate_cli_path, @@ -505,6 +510,7 @@ def create_client( # Collect env vars to pass to SDK (ANTHROPIC_BASE_URL, CLAUDE_CONFIG_DIR, etc.) sdk_env = get_sdk_env_vars() +<<<<<<< HEAD # Get the config dir for profile-specific credential lookup # CLAUDE_CONFIG_DIR enables per-profile Keychain entries with SHA256-hashed service names config_dir = sdk_env.get("CLAUDE_CONFIG_DIR") @@ -532,6 +538,16 @@ def create_client( ) else: logger.info("[Fast Mode] inactive — not requested for this client") +======= + # CRITICAL: Clear git environment variables from os.environ BEFORE SDK instantiation. + # The SDK merges os.environ with our env dict, so contaminated git vars (GIT_INDEX_FILE, + # GIT_DIR, etc.) inherited from parent processes would leak through and cause + # git operation errors in worktree operations. + # We must DELETE these vars from os.environ, not set them to "" (empty string is a value + # that git interprets as "use empty path", which fails). + for var in GIT_ENV_VARS_TO_CLEAR: + os.environ.pop(var, None) +>>>>>>> refs/remotes/upstream/pr/1599 # Debug: Log git-bash path detection on Windows if "CLAUDE_CODE_GIT_BASH_PATH" in sdk_env: diff --git a/apps/frontend/src/main/agent/agent-process.ts b/apps/frontend/src/main/agent/agent-process.ts index 58f9731674..d07a22250d 100644 --- a/apps/frontend/src/main/agent/agent-process.ts +++ b/apps/frontend/src/main/agent/agent-process.ts @@ -24,6 +24,7 @@ import { readSettingsFile } from '../settings-utils'; import type { AppSettings } from '../../shared/types/settings'; import { getOAuthModeClearVars } from './env-utils'; import { getAugmentedEnv } from '../env-utils'; +import { getIsolatedGitEnv } from '../utils/git-isolation'; import { getToolInfo, getClaudeCliPathForSdk } from '../cli-tool-manager'; import { killProcessGracefully, isWindows } from '../platform'; import { debugLog } from '../../shared/utils/debug-logger'; @@ -203,8 +204,11 @@ export class AgentProcessManager { }); // Use getAugmentedEnv() to ensure common tool paths (dotnet, homebrew, etc.) - // are available even when app is launched from Finder/Dock - const augmentedEnv = getAugmentedEnv(); + // are available even when app is launched from Finder/Dock. + // Wrap with getIsolatedGitEnv() to clear GIT_DIR, GIT_WORK_TREE, GIT_INDEX_FILE, + // and other git env vars that can contaminate worktree operations when inherited + // from parent processes (pre-commit hooks, IDE integrations, Electron app). + const augmentedEnv = getIsolatedGitEnv(getAugmentedEnv()); // On Windows, detect and pass git-bash path for Claude Code CLI // Electron can detect git via where.exe, but Python subprocess may not have the same PATH