namespace ClaudeDo.Data.Models; public enum TaskStatus { Idle, Queued, Running, WaitingForReview, WaitingForChildren, Done, Failed, Cancelled, } public enum PlanningPhase { None, Active, Finalized, } public sealed class TaskEntity { public required string Id { get; init; } // Global, monotonically increasing, never-reused display/lookup handle shown as `#123`. // Allocated by TaskNumberAllocator from AppSettingsEntity.NextTaskNumber -- never MAX(number)+1, // which would reissue a deleted task's number. The GUID Id stays the real identity everywhere else. public int Number { get; set; } public required string ListId { get; init; } public required string Title { get; set; } public string? Description { get; set; } public TaskStatus Status { get; set; } = TaskStatus.Idle; public PlanningPhase PlanningPhase { get; set; } = PlanningPhase.None; public string? BlockedByTaskId { get; set; } // A user/MCP-declared predecessor, distinct from BlockedByTaskId (the planning chain's own // internal link): the picker also skips a Queued task while this is set and the referenced // task's Status isn't Done. Unlike the chain, a Failed/Cancelled dependency does NOT cascade // or auto-resolve -- the dependent just stays blocked and reports why (see TaskStateService. // SetDependsOnAsync and QueuePicker). public string? DependsOnTaskId { get; set; } public DateTime? ScheduledFor { get; set; } public string? Result { get; set; } public string? ReviewFeedback { get; set; } public int RoadblockCount { get; set; } // Denormalized from the failing run, same pattern as RoadblockCount, so get_task/ // batch_get_tasks can report why a Failed task stopped without a second query. // Null on a non-Failed task, or on a Failed task predating this field ("unknown"). public string? FailureReason { get; set; } public int? FailureTurnsUsed { get; set; } public int? FailureMaxTurns { get; set; } public string? LogPath { get; set; } public required DateTime CreatedAt { get; init; } public DateTime? StartedAt { get; set; } public DateTime? FinishedAt { get; set; } public string CommitType { get; set; } = CommitTypeRegistry.DefaultType; public string? Model { get; set; } public string? SystemPrompt { get; set; } public string? AgentPath { get; set; } public int? MaxTurns { get; set; } public bool IsStarred { get; set; } public bool IsMyDay { get; set; } // Manual = a reminder only the user can do. Automation skips it (queue picker, daily prep, // list handler) and the Claude affordances are hidden; a hand-driven ConPTY session is still // allowed. New tasks in a manual list default to true. public bool IsManual { get; set; } public string? Notes { get; set; } public int SortOrder { get; set; } public string? SessionSkills { get; set; } // Newline-separated declared file paths/globs this task expects to touch. User-supplied only // (never inferred). Only consulted by the queue picker when the list's // ListConfigEntity.SerializeOnFileOverlap is on, and only for this task's own overlap check -- // an unset value means "no basis to hold this task back", not "touches nothing". public string? ScopeGlobs { get; set; } // Review range for a worktree-less task hosting an interactive "list handler" run // (Mission Control's "Let Claude handle it"): the handler commits its own changes // straight to the list's working dir, so there is no per-task worktree to diff. These // capture the repo's HEAD at session start / submit-for-review instead, so the normal // diff/get_task_diff paths can show `HandlerBaseCommit..HandlerHeadCommit` over the // list's working dir exactly like a merged task's commit-range diff. public string? HandlerBaseCommit { get; set; } public string? HandlerHeadCommit { get; set; } // The claude session id an embedded ConPTY interactive task session is (or was last) // running under -- generated up front and persisted before launch so a closed/aborted // session can be resumed even if the process never got past startup. Cleared implicitly // whenever the task's worktree is recreated (a fresh worktree has nothing to resume into). public string? InteractiveSessionId { get; set; } public string? ParentTaskId { get; set; } public string? PlanningSessionId { get; set; } public string? PlanningSessionToken { get; set; } public DateTime? PlanningFinalizedAt { get; set; } public string? CreatedBy { get; set; } // Navigation properties public ListEntity List { get; set; } = null!; public WorktreeEntity? Worktree { get; set; } public ICollection Runs { get; set; } = new List(); public ICollection Subtasks { get; set; } = new List(); public TaskEntity? Parent { get; set; } public ICollection Children { get; set; } = new List(); }