From 1f36e2312d316969db65a601ac7d9793fbc3bc4c Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Sun, 8 Mar 2026 20:16:00 +0000 Subject: feat: rename working_dir→project_dir; git sandbox execution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ClaudeConfig.WorkingDir → ProjectDir (json: project_dir) - UnmarshalJSON fallback reads legacy working_dir from DB records - New executions with project_dir clone into a temp sandbox via git clone --local - Non-git project_dirs get git init + initial commit before clone - After success: verify clean working tree, merge --ff-only back to project_dir, remove sandbox - On failure/BLOCKED: sandbox preserved, path included in error message - Resume executions run directly in project_dir (no re-clone) Co-Authored-By: Claude Sonnet 4.6 --- internal/api/elaborate.go | 12 ++++++------ internal/api/elaborate_test.go | 2 +- internal/api/validate.go | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'internal/api') diff --git a/internal/api/elaborate.go b/internal/api/elaborate.go index 00f3297..e480e00 100644 --- a/internal/api/elaborate.go +++ b/internal/api/elaborate.go @@ -14,9 +14,9 @@ import ( const elaborateTimeout = 30 * time.Second func buildElaboratePrompt(workDir string) string { - workDirLine := ` "working_dir": string — leave empty unless you have a specific reason to set it,` + workDirLine := ` "project_dir": string — leave empty unless you have a specific reason to set it,` if workDir != "" { - workDirLine = fmt.Sprintf(` "working_dir": string — use %q for tasks that operate on this codebase, empty string otherwise,`, workDir) + workDirLine = fmt.Sprintf(` "project_dir": string — use %q for tasks that operate on this codebase, empty string otherwise,`, workDir) } return `You are a task configuration assistant for Claudomator, an AI task runner that executes tasks by running Claude as a subprocess. @@ -53,7 +53,7 @@ type elaboratedTask struct { type elaboratedClaude struct { Model string `json:"model"` Instructions string `json:"instructions"` - WorkingDir string `json:"working_dir"` + ProjectDir string `json:"project_dir"` MaxBudgetUSD float64 `json:"max_budget_usd"` AllowedTools []string `json:"allowed_tools"` } @@ -87,7 +87,7 @@ func (s *Server) claudeBinaryPath() string { func (s *Server) handleElaborateTask(w http.ResponseWriter, r *http.Request) { var input struct { Prompt string `json:"prompt"` - WorkingDir string `json:"working_dir"` + ProjectDir string `json:"project_dir"` } if err := json.NewDecoder(r.Body).Decode(&input); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid JSON: " + err.Error()}) @@ -99,8 +99,8 @@ func (s *Server) handleElaborateTask(w http.ResponseWriter, r *http.Request) { } workDir := s.workDir - if input.WorkingDir != "" { - workDir = input.WorkingDir + if input.ProjectDir != "" { + workDir = input.ProjectDir } ctx, cancel := context.WithTimeout(r.Context(), elaborateTimeout) diff --git a/internal/api/elaborate_test.go b/internal/api/elaborate_test.go index 52f7fdf..09f7fbe 100644 --- a/internal/api/elaborate_test.go +++ b/internal/api/elaborate_test.go @@ -56,7 +56,7 @@ func TestElaborateTask_Success(t *testing.T) { Claude: elaboratedClaude{ Model: "sonnet", Instructions: "Run go test -race ./... and report results.", - WorkingDir: "", + ProjectDir: "", MaxBudgetUSD: 0.5, AllowedTools: []string{"Bash"}, }, diff --git a/internal/api/validate.go b/internal/api/validate.go index d8ebde9..4b691a9 100644 --- a/internal/api/validate.go +++ b/internal/api/validate.go @@ -56,7 +56,7 @@ func (s *Server) handleValidateTask(w http.ResponseWriter, r *http.Request) { Name string `json:"name"` Claude struct { Instructions string `json:"instructions"` - WorkingDir string `json:"working_dir"` + ProjectDir string `json:"project_dir"` AllowedTools []string `json:"allowed_tools"` } `json:"claude"` } @@ -74,8 +74,8 @@ func (s *Server) handleValidateTask(w http.ResponseWriter, r *http.Request) { } userMsg := fmt.Sprintf("Task name: %s\n\nInstructions:\n%s", input.Name, input.Claude.Instructions) - if input.Claude.WorkingDir != "" { - userMsg += fmt.Sprintf("\n\nWorking directory: %s", input.Claude.WorkingDir) + if input.Claude.ProjectDir != "" { + userMsg += fmt.Sprintf("\n\nWorking directory: %s", input.Claude.ProjectDir) } if len(input.Claude.AllowedTools) > 0 { userMsg += fmt.Sprintf("\n\nAllowed tools: %v", input.Claude.AllowedTools) -- cgit v1.2.3