Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions cmd/task/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,7 @@ Examples:
createCmd.Flags().String("effort", "", "Per-task Claude effort override: low, medium, high, xhigh, max (default: Claude's global default)")
createCmd.Flags().BoolP("execute", "x", false, "Queue task for immediate execution")
createCmd.Flags().Bool("dangerous", false, "Execute in dangerous mode (alias for --permission-mode dangerous)")
createCmd.Flags().String("permission-mode", "", "Permission mode: default (prompt), auto (auto-accept edits), dangerous (skip all). Defaults to the project's setting")
createCmd.Flags().String("permission-mode", "", "Permission mode: default (prompt), accept-edits (auto-accept file edits, still prompt for risky actions; alias: auto), dangerous (skip all). Defaults to the project's setting")
createCmd.Flags().String("tags", "", "Task tags (comma-separated)")
createCmd.Flags().Bool("pinned", false, "Pin the task to the top of its column")
createCmd.Flags().StringP("branch", "b", "", "Existing branch to checkout for worktree (e.g., fix/ui-overflow)")
Expand Down Expand Up @@ -1602,13 +1602,13 @@ Examples:
case db.PermissionModeDangerous:
msg += " (dangerous mode)"
case db.PermissionModeAuto:
msg += " (auto mode)"
msg += " (accept-edits mode)"
}
fmt.Println(successStyle.Render(msg))
},
}
executeCmd.Flags().Bool("dangerous", false, "Execute in dangerous mode (alias for --permission-mode dangerous)")
executeCmd.Flags().String("permission-mode", "", "Override permission mode: default (prompt), auto (auto-accept edits), dangerous (skip all)")
executeCmd.Flags().String("permission-mode", "", "Override permission mode: default (prompt), accept-edits (auto-accept file edits; alias: auto), dangerous (skip all)")
rootCmd.AddCommand(executeCmd)

statusCmd := &cobra.Command{
Expand Down Expand Up @@ -2532,7 +2532,7 @@ Examples:
projectsCreateCmd.Flags().StringP("color", "c", "", "Hex color for display (e.g., #61AFEF)")
projectsCreateCmd.Flags().StringP("aliases", "a", "", "Comma-separated aliases for lookup")
projectsCreateCmd.Flags().String("claude-config-dir", "", "Override CLAUDE_CONFIG_DIR for this project")
projectsCreateCmd.Flags().String("permission-mode", "", "Default permission mode for tasks: default (prompt), auto (auto-accept edits), dangerous (skip all)")
projectsCreateCmd.Flags().String("permission-mode", "", "Default permission mode for tasks: default (prompt), accept-edits (auto-accept file edits; alias: auto), dangerous (skip all)")
projectsCreateCmd.Flags().Bool("no-git", false, "Disable git worktrees (for non-git projects)")
projectsCreateCmd.Flags().Bool("json", false, "Output in JSON format")
projectsCreateCmd.MarkFlagRequired("path")
Expand Down Expand Up @@ -2590,7 +2590,7 @@ Examples:
projectsUpdateCmd.Flags().StringP("aliases", "a", "", "Comma-separated aliases for lookup")
projectsUpdateCmd.Flags().String("claude-config-dir", "", "Override CLAUDE_CONFIG_DIR for this project")
projectsUpdateCmd.Flags().String("context", "", "Cached project context summary")
projectsUpdateCmd.Flags().String("permission-mode", "", "Default permission mode for tasks: default (prompt), auto (auto-accept edits), dangerous (skip all)")
projectsUpdateCmd.Flags().String("permission-mode", "", "Default permission mode for tasks: default (prompt), accept-edits (auto-accept file edits; alias: auto), dangerous (skip all)")
projectsUpdateCmd.Flags().Bool("no-git", false, "Disable git worktrees (for non-git projects)")
projectsUpdateCmd.Flags().Bool("git", false, "Enable git worktrees (default)")
projectsUpdateCmd.Flags().Bool("json", false, "Output in JSON format")
Expand Down Expand Up @@ -5700,7 +5700,7 @@ func updateProjectCLI(currentName, newName, path, instructions, color, aliases,
if permissionMode != "" {
normalized := db.NormalizePermissionMode(permissionMode)
if normalized == "" {
fmt.Fprintln(os.Stderr, errorStyle.Render("Error: invalid permission mode (use default, auto, or dangerous)"))
fmt.Fprintln(os.Stderr, errorStyle.Render("Error: invalid permission mode (use default, accept-edits, or dangerous)"))
os.Exit(1)
}
project.DefaultPermissionMode = normalized
Expand Down
16 changes: 10 additions & 6 deletions internal/db/permission_mode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@ import (

func TestNormalizePermissionMode(t *testing.T) {
cases := map[string]string{
"auto": PermissionModeAuto,
"dangerous": PermissionModeDangerous,
"default": PermissionModeDefault,
"prompt": PermissionModeDefault,
"": "",
"bogus": "",
"auto": PermissionModeAuto, // legacy alias, kept for back-compat
"accept-edits": PermissionModeAuto, // unambiguous spelling normalizes to the canonical value
"accept_edits": PermissionModeAuto,
"acceptEdits": PermissionModeAuto, // Claude Code's own spelling
" Auto ": PermissionModeAuto, // trimmed + case-insensitive
"dangerous": PermissionModeDangerous,
"default": PermissionModeDefault,
"prompt": PermissionModeDefault,
"": "",
"bogus": "",
}
for in, want := range cases {
if got := NormalizePermissionMode(in); got != want {
Expand Down
37 changes: 28 additions & 9 deletions internal/db/tasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type Task struct {
PRNumber int // Pull request number (if associated with a PR)
PRInfoJSON string // Cached PR state as JSON (state, checks, mergeable, etc.)
DangerousMode bool // Whether task is running in dangerous mode (--dangerously-skip-permissions). Kept for backward compat; PermissionMode is authoritative.
PermissionMode string // Permission mode for execution: "default" (prompt), "auto" (acceptEdits), "dangerous" (skip permissions). Empty falls back to DangerousMode/global default.
PermissionMode string // Permission mode for execution: "default" (prompt), "auto"/"accept-edits" (Claude's acceptEdits — auto-accept file edits, still prompts for risky actions), "dangerous" (skip permissions). Empty falls back to DangerousMode/global default.
Pinned bool // Whether the task is pinned to the top of its column
Tags string // Comma-separated tags for categorization (e.g., "customer-support,email,influence-kit")
SourceBranch string // Existing branch to checkout for worktree (e.g., "fix/ui-overflow") instead of creating new branch
Expand Down Expand Up @@ -68,24 +68,43 @@ func IsInProgress(status string) bool {
}

// Permission modes control how the underlying agent handles permission prompts.
//
// IMPORTANT: the stored value "auto" is historical — it predates Claude Code's
// own "auto mode" (the agentic permission flow gated by --enable-auto-mode).
// In TaskYou, "auto" means Claude Code's ACCEPT-EDITS mode (--permission-mode
// acceptEdits): auto-accept file edits while still prompting for risky actions.
// It is NOT Claude Code's --enable-auto-mode. To avoid that overloaded word,
// surface this mode to users and agents as "accept edits" / "accept-edits";
// the "auto" value is kept only for back-compat (and accepted as an alias).
const (
// PermissionModeDefault prompts for permissions (the historical default).
PermissionModeDefault = "default"
// PermissionModeAuto auto-accepts file edits but still gates risky actions
// (Claude's --permission-mode acceptEdits). This is the "auto mode" most
// users want: handles ~99% of permission prompts without the risk of
// fully bypassing permissions.
// PermissionModeAuto maps to Claude Code's accept-edits mode
// (--permission-mode acceptEdits): auto-accept file edits but still gate
// risky actions. This is the low-friction mode most users want — it handles
// ~99% of permission prompts without fully bypassing permissions. Despite
// the stored "auto" value, this is NOT Claude Code's --enable-auto-mode;
// display it as "accept edits" (see PermissionModeAutoLabel).
PermissionModeAuto = "auto"
// PermissionModeDangerous bypasses all permission checks
// (Claude's --dangerously-skip-permissions).
PermissionModeDangerous = "dangerous"
)

// PermissionModeAutoLabel is the unambiguous human-facing name for
// PermissionModeAuto. We deliberately avoid the word "auto" in UI and prompts
// because it collides with Claude Code's separate "auto mode"
// (--enable-auto-mode), which TaskYou does not currently expose.
const PermissionModeAutoLabel = "accept-edits"

// NormalizePermissionMode coerces a raw value into a known permission mode.
// "prompt" and "" are treated as default; unknown values return "".
// "prompt" and "" are treated as default. The unambiguous "accept-edits" name
// (and its variants, plus Claude's own "acceptEdits") all map to the canonical
// PermissionModeAuto value, so callers can use the clearer spelling while old
// "auto" values keep working. Unknown values return "".
func NormalizePermissionMode(mode string) string {
switch mode {
case PermissionModeAuto:
switch strings.ToLower(strings.TrimSpace(mode)) {
case PermissionModeAuto, PermissionModeAutoLabel, "accept_edits", "acceptedits":
return PermissionModeAuto
case PermissionModeDangerous:
return PermissionModeDangerous
Expand Down Expand Up @@ -124,7 +143,7 @@ func (t *Task) IsDangerous() bool {
return t.EffectivePermissionMode() == PermissionModeDangerous
}

// IsAutoPermission reports whether the task runs in auto (acceptEdits) mode.
// IsAutoPermission reports whether the task runs in accept-edits (acceptEdits) mode.
func (t *Task) IsAutoPermission() bool {
return t.EffectivePermissionMode() == PermissionModeAuto
}
Expand Down
2 changes: 1 addition & 1 deletion internal/executor/claude_executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func (c *ClaudeExecutor) ResumeProcess(taskID int64) bool {

// BuildCommand returns the shell command to start an interactive Claude session.
func (c *ClaudeExecutor) BuildCommand(task *db.Task, sessionID, prompt string) string {
// Build permission mode flag (dangerous, auto/acceptEdits, or none)
// Build permission mode flag (dangerous, accept-edits/acceptEdits, or none)
dangerousFlag := claudePermissionFlag(task)

// Build per-task effort override flag (empty = use Claude's global default)
Expand Down
1 change: 1 addition & 0 deletions internal/executor/permission_flag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ func TestClaudePermissionFlag(t *testing.T) {
{"default empty", &db.Task{}, ""},
{"explicit default", &db.Task{PermissionMode: db.PermissionModeDefault}, ""},
{"auto", &db.Task{PermissionMode: db.PermissionModeAuto}, "--permission-mode acceptEdits "},
{"accept-edits alias", &db.Task{PermissionMode: "accept-edits"}, "--permission-mode acceptEdits "},
{"dangerous", &db.Task{PermissionMode: db.PermissionModeDangerous}, "--dangerously-skip-permissions "},
{"legacy dangerous bool", &db.Task{DangerousMode: true}, "--dangerously-skip-permissions "},
}
Expand Down
4 changes: 2 additions & 2 deletions internal/mcp/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,8 @@ func (s *Server) handleRequest(req *jsonRPCRequest) {
},
"permission_mode": map[string]interface{}{
"type": "string",
"description": "Permission mode for execution: 'default' (prompt), 'auto' (auto-accept edits), or 'dangerous' (skip all prompts). Defaults to the project's configured default.",
"enum": []string{"default", "auto", "dangerous"},
"description": "Permission mode for execution: 'default' (prompt for each permission), 'accept-edits' (Claude Code's acceptEdits / --permission-mode acceptEdits: auto-accept file edits but still prompt for risky actions — this is NOT Claude Code's separate 'auto mode' from --enable-auto-mode), or 'dangerous' (skip all prompts / --dangerously-skip-permissions). The legacy value 'auto' is still accepted and means the same as 'accept-edits'. Defaults to the project's configured default.",
"enum": []string{"default", "accept-edits", "dangerous"},
},
},
"required": []string{"title"},
Expand Down
2 changes: 1 addition & 1 deletion internal/ui/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -2900,7 +2900,7 @@ func (m *AppModel) updateNewTaskForm(msg tea.Msg) (tea.Model, tea.Cmd) {
Options(
huh.NewOption("No — save to backlog", "no"),
huh.NewOption("Yes — execute now", "yes"),
huh.NewOption("Yes — execute in auto mode", "auto"),
huh.NewOption("Yes — execute in accept-edits mode", "auto"),
huh.NewOption("Yes — execute in dangerous mode", "dangerous"),
).
Value(&m.queueValue),
Expand Down
6 changes: 4 additions & 2 deletions internal/ui/detail.go
Original file line number Diff line number Diff line change
Expand Up @@ -2358,7 +2358,9 @@ func (m *DetailModel) renderHeader() string {
meta.WriteString(" ")
}

// Auto mode badge (acceptEdits) for active tasks.
// Accept-edits badge (Claude's acceptEdits mode) for active tasks. Labeled
// "ACCEPT EDITS" rather than "AUTO" so it isn't confused with Claude Code's
// separate auto mode (--enable-auto-mode).
if t.IsAutoPermission() && (t.Status == db.StatusProcessing || t.Status == db.StatusBlocked) {
var autoStyle lipgloss.Style
if m.focused {
Expand All @@ -2373,7 +2375,7 @@ func (m *DetailModel) renderHeader() string {
Background(dimmedBg).
Foreground(dimmedFg)
}
meta.WriteString(autoStyle.Render("AUTO"))
meta.WriteString(autoStyle.Render("ACCEPT EDITS"))
meta.WriteString(" ")
}

Expand Down
2 changes: 1 addition & 1 deletion internal/ui/kanban.go
Original file line number Diff line number Diff line change
Expand Up @@ -1165,7 +1165,7 @@ func (k *KanbanBoard) renderTaskCard(task *db.Task, width int, isSelected bool,
indicators = append(indicators, dangerStyle.Render("●"))
}
}
// Auto mode indicator (green dot) for active tasks running in auto/acceptEdits mode.
// Accept-edits indicator (green dot) for active tasks running in Claude's acceptEdits mode.
if task.IsAutoPermission() && (task.Status == db.StatusProcessing || task.Status == db.StatusBlocked) {
if isSelected {
indicators = append(indicators, "●")
Expand Down
8 changes: 4 additions & 4 deletions internal/ui/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,8 @@ func (m *SettingsModel) showProjectForm(project *db.Project) (*SettingsModel, te
m.projectFormUseWorktrees = project.UseWorktrees

// Default permission mode. Use the project's explicit setting when present,
// otherwise pre-select the effective default (auto) so the form mirrors the
// mode tasks will actually run in.
// otherwise pre-select the effective default (accept-edits) so the form
// mirrors the mode tasks will actually run in.
m.projectFormPermissionMode = db.NormalizePermissionMode(project.DefaultPermissionMode)
if m.projectFormPermissionMode == "" {
m.projectFormPermissionMode = project.EffectiveDefaultPermissionMode()
Expand Down Expand Up @@ -342,9 +342,9 @@ func (m *SettingsModel) showProjectForm(project *db.Project) (*SettingsModel, te
huh.NewSelect[string]().
Key("permission_mode").
Title("Default Permission Mode").
Description("How new tasks handle permissions. Auto handles ~99% without prompting.").
Description("How new tasks handle permissions. Accept Edits handles ~99% without prompting.").
Options(
huh.NewOption("Auto — auto-accept edits (recommended)", db.PermissionModeAuto),
huh.NewOption("Accept Edits — auto-accept file edits, still prompt for risky actions (recommended)", db.PermissionModeAuto),
huh.NewOption("Prompt — ask for each permission", db.PermissionModeDefault),
huh.NewOption("Dangerous — skip all permission checks", db.PermissionModeDangerous),
).
Expand Down
Loading