diff --git a/shell/llm/claudecode.go b/shell/llm/claudecode.go index f410f5c..95c7e87 100644 --- a/shell/llm/claudecode.go +++ b/shell/llm/claudecode.go @@ -58,6 +58,26 @@ func NewClaudeCodeComplete(cfg config.ClaudeCodeCfg, log *slog.Logger) coretypes timeout = defaultClaudeTimeout } + // Resolve working directory once at init time. + workDir := cfg.WorkingDir + if workDir == "" { + tmp, err := os.MkdirTemp("", "claude-agent-*") + if err != nil { + log.Error("claude-code: failed to create temp working dir", "err", err) + // Fall through — cmd.Dir will remain empty (inherits CWD). + } else { + workDir = tmp + log.Warn("claude-code working_dir is empty, using temporary directory", + "dir", workDir, + ) + } + } else { + // Ensure configured directory exists. + if err := os.MkdirAll(workDir, 0o755); err != nil { + log.Error("claude-code: failed to create working dir", "dir", workDir, "err", err) + } + } + return func(ctx context.Context, req coretypes.CompletionRequest) (coretypes.CompletionResponse, error) { ctx, cancel := context.WithTimeout(ctx, timeout) defer cancel() @@ -70,11 +90,12 @@ func NewClaudeCodeComplete(cfg config.ClaudeCodeCfg, log *slog.Logger) coretypes "binary", binary, "args", strings.Join(args, " "), "prompt_len", len(prompt), + "working_dir", workDir, ) cmd := exec.CommandContext(ctx, binary, args...) - if cfg.WorkingDir != "" { - cmd.Dir = cfg.WorkingDir + if workDir != "" { + cmd.Dir = workDir } // Build clean env: inherit parent but remove ANTHROPIC_API_KEY // so claude uses its own OAuth auth instead of a potentially invalid key.