@@ -1076,9 +1076,16 @@ type Project struct {
10761076 Actions []ProjectAction // actions triggered on task events (stored as JSON)
10771077 Color string // hex color for display (e.g., "#61AFEF")
10781078 ClaudeConfigDir string // override CLAUDE_CONFIG_DIR for this project
1079+ UseWorktrees bool // whether to use git worktrees for task isolation (default true)
10791080 CreatedAt LocalTime
10801081}
10811082
1083+ // UsesWorktrees returns whether this project uses git worktrees for task isolation.
1084+ // Defaults to true for backward compatibility.
1085+ func (p * Project ) UsesWorktrees () bool {
1086+ return p .UseWorktrees
1087+ }
1088+
10821089// GetAction returns the action for a given trigger, or nil if not found.
10831090func (p * Project ) GetAction (trigger string ) * ProjectAction {
10841091 for i := range p .Actions {
@@ -1092,10 +1099,14 @@ func (p *Project) GetAction(trigger string) *ProjectAction {
10921099// CreateProject creates a new project.
10931100func (db * DB ) CreateProject (p * Project ) error {
10941101 actionsJSON , _ := json .Marshal (p .Actions )
1102+ useWorktrees := 1
1103+ if ! p .UseWorktrees {
1104+ useWorktrees = 0
1105+ }
10951106 result , err := db .Exec (`
1096- INSERT INTO projects (name, path, aliases, instructions, actions, color, claude_config_dir)
1097- VALUES (?, ?, ?, ?, ?, ?, ?)
1098- ` , p .Name , p .Path , p .Aliases , p .Instructions , string (actionsJSON ), p .Color , p .ClaudeConfigDir )
1107+ INSERT INTO projects (name, path, aliases, instructions, actions, color, claude_config_dir, use_worktrees )
1108+ VALUES (?, ?, ?, ?, ?, ?, ?, ? )
1109+ ` , p .Name , p .Path , p .Aliases , p .Instructions , string (actionsJSON ), p .Color , p .ClaudeConfigDir , useWorktrees )
10991110 if err != nil {
11001111 return fmt .Errorf ("insert project: %w" , err )
11011112 }
@@ -1107,10 +1118,14 @@ func (db *DB) CreateProject(p *Project) error {
11071118// UpdateProject updates a project.
11081119func (db * DB ) UpdateProject (p * Project ) error {
11091120 actionsJSON , _ := json .Marshal (p .Actions )
1121+ useWorktrees := 1
1122+ if ! p .UseWorktrees {
1123+ useWorktrees = 0
1124+ }
11101125 _ , err := db .Exec (`
1111- UPDATE projects SET name = ?, path = ?, aliases = ?, instructions = ?, actions = ?, color = ?, claude_config_dir = ?
1126+ UPDATE projects SET name = ?, path = ?, aliases = ?, instructions = ?, actions = ?, color = ?, claude_config_dir = ?, use_worktrees = ?
11121127 WHERE id = ?
1113- ` , p .Name , p .Path , p .Aliases , p .Instructions , string (actionsJSON ), p .Color , p .ClaudeConfigDir , p .ID )
1128+ ` , p .Name , p .Path , p .Aliases , p .Instructions , string (actionsJSON ), p .Color , p .ClaudeConfigDir , useWorktrees , p .ID )
11141129 if err != nil {
11151130 return fmt .Errorf ("update project: %w" , err )
11161131 }
@@ -1151,7 +1166,7 @@ func (db *DB) CountTasksByProject(projectName string) (int, error) {
11511166// ListProjects returns all projects, with "personal" always first.
11521167func (db * DB ) ListProjects () ([]* Project , error ) {
11531168 rows , err := db .Query (`
1154- SELECT id, name, path, aliases, instructions, COALESCE(actions, '[]'), COALESCE(color, ''), COALESCE(claude_config_dir, ''), created_at
1169+ SELECT id, name, path, aliases, instructions, COALESCE(actions, '[]'), COALESCE(color, ''), COALESCE(claude_config_dir, ''), COALESCE(use_worktrees, 1), created_at
11551170 FROM projects ORDER BY CASE WHEN name = 'personal' THEN 0 ELSE 1 END, name
11561171 ` )
11571172 if err != nil {
@@ -1163,10 +1178,12 @@ func (db *DB) ListProjects() ([]*Project, error) {
11631178 for rows .Next () {
11641179 p := & Project {}
11651180 var actionsJSON string
1166- if err := rows .Scan (& p .ID , & p .Name , & p .Path , & p .Aliases , & p .Instructions , & actionsJSON , & p .Color , & p .ClaudeConfigDir , & p .CreatedAt ); err != nil {
1181+ var useWorktrees int
1182+ if err := rows .Scan (& p .ID , & p .Name , & p .Path , & p .Aliases , & p .Instructions , & actionsJSON , & p .Color , & p .ClaudeConfigDir , & useWorktrees , & p .CreatedAt ); err != nil {
11671183 return nil , fmt .Errorf ("scan project: %w" , err )
11681184 }
11691185 json .Unmarshal ([]byte (actionsJSON ), & p .Actions )
1186+ p .UseWorktrees = useWorktrees != 0
11701187 projects = append (projects , p )
11711188 }
11721189 return projects , nil
@@ -1177,31 +1194,34 @@ func (db *DB) GetProjectByName(name string) (*Project, error) {
11771194 // First try exact name match
11781195 p := & Project {}
11791196 var actionsJSON string
1197+ var useWorktrees int
11801198 err := db .QueryRow (`
1181- SELECT id, name, path, aliases, instructions, COALESCE(actions, '[]'), COALESCE(color, ''), COALESCE(claude_config_dir, ''), created_at
1199+ SELECT id, name, path, aliases, instructions, COALESCE(actions, '[]'), COALESCE(color, ''), COALESCE(claude_config_dir, ''), COALESCE(use_worktrees, 1), created_at
11821200 FROM projects WHERE name = ?
1183- ` , name ).Scan (& p .ID , & p .Name , & p .Path , & p .Aliases , & p .Instructions , & actionsJSON , & p .Color , & p .ClaudeConfigDir , & p .CreatedAt )
1201+ ` , name ).Scan (& p .ID , & p .Name , & p .Path , & p .Aliases , & p .Instructions , & actionsJSON , & p .Color , & p .ClaudeConfigDir , & useWorktrees , & p .CreatedAt )
11841202 if err == nil {
11851203 json .Unmarshal ([]byte (actionsJSON ), & p .Actions )
1204+ p .UseWorktrees = useWorktrees != 0
11861205 return p , nil
11871206 }
11881207 if err != sql .ErrNoRows {
11891208 return nil , fmt .Errorf ("query project: %w" , err )
11901209 }
11911210
11921211 // Try alias match
1193- rows , err := db .Query (`SELECT id, name, path, aliases, instructions, COALESCE(actions, '[]'), COALESCE(color, ''), COALESCE(claude_config_dir, ''), created_at FROM projects` )
1212+ rows , err := db .Query (`SELECT id, name, path, aliases, instructions, COALESCE(actions, '[]'), COALESCE(color, ''), COALESCE(claude_config_dir, ''), COALESCE(use_worktrees, 1), created_at FROM projects` )
11941213 if err != nil {
11951214 return nil , fmt .Errorf ("query projects: %w" , err )
11961215 }
11971216 defer rows .Close ()
11981217
11991218 for rows .Next () {
12001219 p := & Project {}
1201- if err := rows .Scan (& p .ID , & p .Name , & p .Path , & p .Aliases , & p .Instructions , & actionsJSON , & p .Color , & p .ClaudeConfigDir , & p .CreatedAt ); err != nil {
1220+ if err := rows .Scan (& p .ID , & p .Name , & p .Path , & p .Aliases , & p .Instructions , & actionsJSON , & p .Color , & p .ClaudeConfigDir , & useWorktrees , & p .CreatedAt ); err != nil {
12021221 return nil , fmt .Errorf ("scan project: %w" , err )
12031222 }
12041223 json .Unmarshal ([]byte (actionsJSON ), & p .Actions )
1224+ p .UseWorktrees = useWorktrees != 0
12051225 for _ , alias := range splitAliases (p .Aliases ) {
12061226 if alias == name {
12071227 return p , nil
0 commit comments