summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-03-05 23:17:06 +0000
committerPeter Stone <thepeterstone@gmail.com>2026-03-05 23:17:06 +0000
commita33211d0ad07f5aaf2d8bb51ba18e6790a153bb4 (patch)
tree331380911223bbcd9a5a22d68c38125218147beb /internal
parentf8b5f2580e730a8affbccec8b5bde9b96b1f9fc2 (diff)
executor: default permission_mode to bypassPermissions
claudomator runs tasks unattended; prompting for write permission always stalls execution. Any task without an explicit permission_mode now gets --permission-mode bypassPermissions automatically. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal')
-rw-r--r--internal/executor/claude.go9
-rw-r--r--internal/executor/claude_test.go58
2 files changed, 59 insertions, 8 deletions
diff --git a/internal/executor/claude.go b/internal/executor/claude.go
index 7cbcc6c..d3f5751 100644
--- a/internal/executor/claude.go
+++ b/internal/executor/claude.go
@@ -203,9 +203,14 @@ func (r *ClaudeRunner) buildArgs(t *task.Task) []string {
if t.Claude.MaxBudgetUSD > 0 {
args = append(args, "--max-budget-usd", fmt.Sprintf("%.2f", t.Claude.MaxBudgetUSD))
}
- if t.Claude.PermissionMode != "" {
- args = append(args, "--permission-mode", t.Claude.PermissionMode)
+ // Default to bypassPermissions — claudomator runs tasks unattended, so
+ // prompting for write access would always stall execution. Tasks that need
+ // a more restrictive mode can set permission_mode explicitly.
+ permMode := t.Claude.PermissionMode
+ if permMode == "" {
+ permMode = "bypassPermissions"
}
+ args = append(args, "--permission-mode", permMode)
if t.Claude.SystemPromptAppend != "" {
args = append(args, "--append-system-prompt", t.Claude.SystemPromptAppend)
}
diff --git a/internal/executor/claude_test.go b/internal/executor/claude_test.go
index ac6aabf..edf13b5 100644
--- a/internal/executor/claude_test.go
+++ b/internal/executor/claude_test.go
@@ -23,13 +23,13 @@ func TestClaudeRunner_BuildArgs_BasicTask(t *testing.T) {
args := r.buildArgs(tk)
- expected := []string{"-p", "fix the bug", "--output-format", "stream-json", "--verbose", "--model", "sonnet"}
- if len(args) != len(expected) {
- t.Fatalf("args length: want %d, got %d: %v", len(expected), len(args), args)
+ argMap := make(map[string]bool)
+ for _, a := range args {
+ argMap[a] = true
}
- for i, want := range expected {
- if args[i] != want {
- t.Errorf("arg[%d]: want %q, got %q", i, want, args[i])
+ for _, want := range []string{"-p", "fix the bug", "--output-format", "stream-json", "--verbose", "--model", "sonnet"} {
+ if !argMap[want] {
+ t.Errorf("missing arg %q in %v", want, args)
}
}
}
@@ -76,6 +76,52 @@ func TestClaudeRunner_BuildArgs_FullConfig(t *testing.T) {
}
}
+func TestClaudeRunner_BuildArgs_DefaultsToBypassPermissions(t *testing.T) {
+ r := &ClaudeRunner{}
+ tk := &task.Task{
+ Claude: task.ClaudeConfig{
+ Instructions: "do work",
+ SkipPlanning: true,
+ // PermissionMode intentionally not set
+ },
+ }
+
+ args := r.buildArgs(tk)
+
+ found := false
+ for i, a := range args {
+ if a == "--permission-mode" && i+1 < len(args) && args[i+1] == "bypassPermissions" {
+ found = true
+ }
+ }
+ if !found {
+ t.Errorf("expected --permission-mode bypassPermissions when PermissionMode is empty, args: %v", args)
+ }
+}
+
+func TestClaudeRunner_BuildArgs_RespectsExplicitPermissionMode(t *testing.T) {
+ r := &ClaudeRunner{}
+ tk := &task.Task{
+ Claude: task.ClaudeConfig{
+ Instructions: "do work",
+ PermissionMode: "default",
+ SkipPlanning: true,
+ },
+ }
+
+ args := r.buildArgs(tk)
+
+ for i, a := range args {
+ if a == "--permission-mode" && i+1 < len(args) {
+ if args[i+1] != "default" {
+ t.Errorf("expected --permission-mode default, got %q", args[i+1])
+ }
+ return
+ }
+ }
+ t.Errorf("--permission-mode flag not found in args: %v", args)
+}
+
func TestClaudeRunner_BuildArgs_AlwaysIncludesVerbose(t *testing.T) {
r := &ClaudeRunner{}
tk := &task.Task{