Documentation
¶
Index ¶
- Constants
- Variables
- type ActiveAgent
- type AgentMetrics
- type Broker
- type CompletedAgent
- type ErrTagTaskConflict
- type ErrTagTaskNoPR
- type ErrTagTaskNotFound
- type ErrTagTaskNotPending
- type Event
- type Notifier
- type PlanningEpic
- type PlanningEpicLister
- type PlanningEpicListerFunc
- type Repository
- type StartOverTaskParams
- type Status
- type Store
- func (s *Store) AddCost(ctx context.Context, id TaskID, costUSD float64) error
- func (s *Store) AppendTaskLogs(ctx context.Context, id TaskID, attempt int, logs []string) error
- func (s *Store) BulkCloseTasksByEpic(ctx context.Context, epicID, reason string) error
- func (s *Store) BulkDeleteTasksByEpic(ctx context.Context, epicID string) error
- func (s *Store) BulkDeleteTasksByIDs(ctx context.Context, ids []string) error
- func (s *Store) ClaimPendingTask(ctx context.Context, repoIDs []string) (*Task, error)
- func (s *Store) ClearEpicIDForTasks(ctx context.Context, epicID string) error
- func (s *Store) CloseTask(ctx context.Context, id TaskID, reason string) error
- func (s *Store) CreateTask(ctx context.Context, task *Task) error
- func (s *Store) CreateTaskFromEpic(ctx context.Context, repoID, title, description string, ...) (string, error)
- func (s *Store) DeleteExpiredLogs(ctx context.Context, retention time.Duration) (int64, error)
- func (s *Store) DeleteTask(ctx context.Context, id TaskID) error
- func (s *Store) FeedbackRetryTask(ctx context.Context, id TaskID, feedback string) error
- func (s *Store) GetAgentMetrics(ctx context.Context) (*AgentMetrics, error)
- func (s *Store) HasTasksForRepo(ctx context.Context, repoID string) (bool, error)
- func (s *Store) Heartbeat(ctx context.Context, id TaskID) (bool, error)
- func (s *Store) ListTasks(ctx context.Context) ([]*Task, error)
- func (s *Store) ListTasksByEpic(ctx context.Context, epicID string) ([]*Task, error)
- func (s *Store) ListTasksByRepo(ctx context.Context, repoID string) ([]*Task, error)
- func (s *Store) ListTasksInReview(ctx context.Context) ([]*Task, error)
- func (s *Store) ListTasksInReviewByRepo(ctx context.Context, repoID string) ([]*Task, error)
- func (s *Store) ListTasksInReviewNoPR(ctx context.Context) ([]*Task, error)
- func (s *Store) ManualRetryTask(ctx context.Context, id TaskID, instructions string) error
- func (s *Store) MoveToReview(ctx context.Context, id TaskID) error
- func (s *Store) ReadTask(ctx context.Context, id TaskID) (*Task, error)
- func (s *Store) ReadTaskLogs(ctx context.Context, id TaskID) ([]string, error)
- func (s *Store) ReadTaskStatus(ctx context.Context, idStr string) (string, error)
- func (s *Store) RemoveDependency(ctx context.Context, id TaskID, depID string) error
- func (s *Store) RetryTask(ctx context.Context, id TaskID, category, reason string) error
- func (s *Store) ScheduleRetry(ctx context.Context, id TaskID, reason string) error
- func (s *Store) SetAgentStatus(ctx context.Context, id TaskID, status string) error
- func (s *Store) SetCloseReason(ctx context.Context, id TaskID, reason string) error
- func (s *Store) SetPlanningEpicLister(lister PlanningEpicLister)
- func (s *Store) SetReady(ctx context.Context, id TaskID, ready bool) error
- func (s *Store) SetRetryContext(ctx context.Context, id TaskID, retryCtx string) error
- func (s *Store) SetTaskBranch(ctx context.Context, id TaskID, branchName string) error
- func (s *Store) SetTaskPullRequest(ctx context.Context, id TaskID, prURL string, prNumber int) error
- func (s *Store) StartOverTask(ctx context.Context, id TaskID, params StartOverTaskParams) (*Task, error)
- func (s *Store) StopTask(ctx context.Context, id TaskID, reason string) error
- func (s *Store) StreamTaskLogs(ctx context.Context, id TaskID, fn func(attempt int, lines []string) error) error
- func (s *Store) Subscribe() chan Event
- func (s *Store) TimeoutStaleTasks(ctx context.Context, timeout time.Duration) (int, error)
- func (s *Store) Unsubscribe(ch chan Event)
- func (s *Store) UpdatePendingTask(ctx context.Context, id TaskID, params UpdatePendingTaskParams) error
- func (s *Store) UpdateTaskStatus(ctx context.Context, id TaskID, status Status) error
- func (s *Store) WaitForPending() <-chan struct{}
- type Task
- type TaskID
- type TaskRepository
- type UpdatePendingTaskParams
Constants ¶
const ( EventTaskCreated = "task_created" EventTaskUpdated = "task_updated" EventTaskDeleted = "task_deleted" EventLogsAppended = "logs_appended" )
EventType identifies the kind of SSE event.
Variables ¶
var ErrTaskNoPR = errtag.Tag[ErrTagTaskNoPR]( errors.New("task has no pull request or branch"), )
ErrTaskNoPR is returned when a move-to-review is attempted on a failed task that has no PR or branch.
var ErrTaskNotFailed = errtag.Tag[ErrTagTaskConflict]( errors.New("task is not in failed status"), )
ErrTaskNotFailed is returned when a move-to-review is attempted on a task that is not in failed status.
var ErrTaskNotPending = errtag.Tag[ErrTagTaskNotPending]( errors.New("task is no longer pending"), )
ErrTaskNotPending is returned when an update is attempted on a task that is no longer in pending status.
Functions ¶
This section is empty.
Types ¶
type ActiveAgent ¶
type ActiveAgent struct {
TaskID string `json:"task_id"`
TaskTitle string `json:"task_title"`
RepoID string `json:"repo_id"`
StartedAt string `json:"started_at"`
RunningFor int64 `json:"running_for_ms"`
Attempt int `json:"attempt"`
CostUSD float64 `json:"cost_usd"`
Model string `json:"model,omitempty"`
EpicID string `json:"epic_id,omitempty"`
IsPlanning bool `json:"is_planning,omitempty"`
EpicTitle string `json:"epic_title,omitempty"`
}
ActiveAgent describes a single running agent session.
type AgentMetrics ¶
type AgentMetrics struct {
// Currently running agents
RunningAgents int `json:"running_agents"`
// Tasks pending to be picked up
PendingTasks int `json:"pending_tasks"`
// Tasks in review (PR created, awaiting merge)
ReviewTasks int `json:"review_tasks"`
// Total tasks (all statuses)
TotalTasks int `json:"total_tasks"`
// Completed tasks (merged + closed)
CompletedTasks int `json:"completed_tasks"`
// Failed tasks
FailedTasks int `json:"failed_tasks"`
// Total cost across all tasks (USD)
TotalCostUSD float64 `json:"total_cost_usd"`
// Details about each currently running agent
ActiveAgents []ActiveAgent `json:"active_agents"`
// Recent completions (last 10 tasks that reached a terminal state)
RecentCompletions []CompletedAgent `json:"recent_completions"`
// Workers actively polling for tasks
Workers []workertracker.WorkerInfo `json:"workers"`
}
AgentMetrics provides a snapshot of agent activity and performance.
type Broker ¶
type Broker struct {
// contains filtered or unexported fields
}
Broker fans out task events to SSE subscribers. When a Notifier is configured, events are routed through the external notification system so that multiple server instances can share events. When nil, events are fanned out directly in-process.
func NewBroker ¶
NewBroker creates a new Broker. If notifier is non-nil, Publish sends events through the external notification system; otherwise events are fanned out locally.
func (*Broker) Publish ¶
Publish sends an event. If a notifier is configured, the event is serialized and sent through the external notification system (the LISTEN side calls Receive to fan out locally). Otherwise, fans out directly to local subscribers.
func (*Broker) Receive ¶
Receive is called by an external listener (e.g., PG LISTEN loop) to inject an event for local fan-out to SSE subscribers.
func (*Broker) Unsubscribe ¶
Unsubscribe removes and closes a subscriber channel.
type CompletedAgent ¶
type CompletedAgent struct {
TaskID string `json:"task_id"`
TaskTitle string `json:"task_title"`
RepoID string `json:"repo_id"`
Status string `json:"status"`
DurationMs *int64 `json:"duration_ms,omitempty"`
CostUSD float64 `json:"cost_usd"`
Attempt int `json:"attempt"`
FinishedAt string `json:"finished_at"`
}
CompletedAgent describes a recently completed agent session.
type ErrTagTaskConflict ¶
ErrTagTaskConflict indicates a task conflict (e.g. duplicate ID).
func (ErrTagTaskConflict) Msg ¶
func (ErrTagTaskConflict) Msg() string
func (ErrTagTaskConflict) Unwrap ¶
func (e ErrTagTaskConflict) Unwrap() error
type ErrTagTaskNoPR ¶
type ErrTagTaskNoPR struct{ errtag.InvalidArgument }
ErrTagTaskNoPR indicates a task has no PR or branch to move to review.
func (ErrTagTaskNoPR) Msg ¶
func (ErrTagTaskNoPR) Msg() string
func (ErrTagTaskNoPR) Unwrap ¶
func (e ErrTagTaskNoPR) Unwrap() error
type ErrTagTaskNotFound ¶
ErrTagTaskNotFound indicates a task was not found.
func (ErrTagTaskNotFound) Msg ¶
func (ErrTagTaskNotFound) Msg() string
func (ErrTagTaskNotFound) Unwrap ¶
func (e ErrTagTaskNotFound) Unwrap() error
type ErrTagTaskNotPending ¶
ErrTagTaskNotPending indicates an operation was rejected because the task is not in pending status.
func (ErrTagTaskNotPending) Msg ¶
func (ErrTagTaskNotPending) Msg() string
func (ErrTagTaskNotPending) Unwrap ¶
func (e ErrTagTaskNotPending) Unwrap() error
type Event ¶
type Event struct {
Type string `json:"type"`
RepoID string `json:"repo_id,omitempty"`
Task *Task `json:"task,omitempty"`
TaskID TaskID `json:"task_id,omitempty"`
Logs []string `json:"logs,omitempty"`
Attempt int `json:"attempt,omitempty"`
}
Event represents a task mutation broadcast to SSE subscribers.
type Notifier ¶
Notifier sends event payloads to an external notification system (e.g., PostgreSQL NOTIFY). The listen side of the notification system calls Broker.Receive to complete the fan-out.
type PlanningEpic ¶
PlanningEpic represents an epic that is actively being planned by an agent. This is a minimal struct to avoid importing the epic package (which would create a circular dependency).
type PlanningEpicLister ¶
type PlanningEpicLister interface {
ListPlanningEpicsForMetrics(ctx context.Context) ([]PlanningEpic, error)
}
PlanningEpicLister lists epics that are actively being planned.
type PlanningEpicListerFunc ¶
type PlanningEpicListerFunc struct {
// contains filtered or unexported fields
}
PlanningEpicListerFunc adapts a function to the PlanningEpicLister interface.
func NewPlanningEpicListerFunc ¶
func NewPlanningEpicListerFunc(fn func(ctx context.Context) ([]PlanningEpic, error)) *PlanningEpicListerFunc
NewPlanningEpicListerFunc creates a PlanningEpicLister from a function.
func (*PlanningEpicListerFunc) ListPlanningEpicsForMetrics ¶
func (f *PlanningEpicListerFunc) ListPlanningEpicsForMetrics(ctx context.Context) ([]PlanningEpic, error)
type Repository ¶
type Repository interface {
TaskRepository
tx.Repository[Repository]
}
Repository is the interface for performing CRUD operations on Tasks.
Implementations must handle all database-specific concerns (error mapping, marshalling) and return domain types.
type StartOverTaskParams ¶
StartOverTaskParams holds the fields that can be updated when starting a task over.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store wraps a Repository and adds application-level concerns such as pending task notification, dependency validation, and event broadcasting.
func NewStore ¶
func NewStore(repo Repository, broker *Broker) *Store
NewStore creates a new Store backed by the given Repository and Broker.
func (*Store) AppendTaskLogs ¶
AppendTaskLogs appends log lines to a task for the given attempt.
func (*Store) BulkCloseTasksByEpic ¶
BulkCloseTasksByEpic closes all non-terminal tasks for an epic and publishes update events for each affected task.
func (*Store) BulkDeleteTasksByEpic ¶
BulkDeleteTasksByEpic deletes all tasks (and their logs) belonging to an epic and publishes deletion events for each affected task.
func (*Store) BulkDeleteTasksByIDs ¶
BulkDeleteTasksByIDs deletes multiple tasks (and their logs) by ID and publishes deletion events for each affected task.
func (*Store) ClaimPendingTask ¶
ClaimPendingTask finds a pending task with all dependencies met and claims it by setting its status to running. When repoIDs is non-empty, only tasks belonging to those repos are considered. The read-check-claim flow is wrapped in a transaction and uses optimistic locking (WHERE status = 'pending') so that concurrent workers cannot claim the same task.
func (*Store) ClearEpicIDForTasks ¶
ClearEpicIDForTasks removes the epic_id foreign key from all tasks belonging to the given epic. This must be called before deleting an epic to avoid FK constraint violations.
func (*Store) CreateTask ¶
CreateTask validates dependencies and creates a new task.
func (*Store) CreateTaskFromEpic ¶
func (s *Store) CreateTaskFromEpic(ctx context.Context, repoID, title, description string, dependsOn, acceptanceCriteria []string, epicID string, ready bool, model string) (string, error)
CreateTaskFromEpic creates a task associated with an epic. Dependencies are not validated since they are created in the same batch.
func (*Store) DeleteExpiredLogs ¶
DeleteExpiredLogs deletes all log entries older than the given retention duration. Returns the number of log batches deleted.
func (*Store) DeleteTask ¶
DeleteTask deletes a task, its logs, and removes it from any other tasks' dependency lists.
func (*Store) FeedbackRetryTask ¶
FeedbackRetryTask transitions a task in review back to pending so the agent can iterate on its solution based on the user's feedback. Unlike ManualRetryTask, it preserves the existing PR/branch so the agent pushes fixes to the same branch.
Feedback retries (manual change requests) do not count towards the max retry attempts because they represent user-driven iteration rather than failure recovery. Both attempt and max_attempts are incremented so the attempt number is unique for log tabbing while keeping the retry budget unchanged.
func (*Store) GetAgentMetrics ¶
func (s *Store) GetAgentMetrics(ctx context.Context) (*AgentMetrics, error)
GetAgentMetrics computes agent observability metrics from current task data.
func (*Store) HasTasksForRepo ¶
HasTasksForRepo checks whether any tasks exist for a given repo.
func (*Store) Heartbeat ¶
Heartbeat updates the last heartbeat time for a running task. Returns true if the task is still running, false if it was stopped, closed, or deleted — signalling the worker to cancel execution.
func (*Store) ListTasksByEpic ¶
ListTasksByEpic returns all tasks belonging to a given epic.
func (*Store) ListTasksByRepo ¶
ListTasksByRepo returns all tasks for a given repo.
func (*Store) ListTasksInReview ¶
ListTasksInReview returns all tasks in review status.
func (*Store) ListTasksInReviewByRepo ¶
ListTasksInReviewByRepo returns tasks in review status for a given repo.
func (*Store) ListTasksInReviewNoPR ¶
ListTasksInReviewNoPR returns tasks in review that have a branch but no PR yet.
func (*Store) ManualRetryTask ¶
ManualRetryTask transitions a failed task back to pending for another attempt. instructions contains optional guidance for the agent on the retry. Previous attempt logs are preserved — the UI shows them in separate tabs.
func (*Store) MoveToReview ¶
MoveToReview transitions a failed task back to review status. This is only allowed when the task has a PR or branch from a previous attempt — the user wants to treat the existing PR as reviewable despite the agent failure.
func (*Store) ReadTaskLogs ¶
ReadTaskLogs reads all logs for a task.
func (*Store) ReadTaskStatus ¶
ReadTaskStatus reads a task's status by its string ID.
func (*Store) RemoveDependency ¶
RemoveDependency removes a dependency from a task. The dependency ID must be a valid task ID. After removal, if the task is pending, a pending notification is sent in case the task is now unblocked.
func (*Store) RetryTask ¶
RetryTask transitions a task from review back to pending for another attempt. category classifies the failure type (e.g. "ci_failure:tests", "merge_conflict") for circuit breaker detection. If the same category fails consecutively >= 3 times, the task is failed immediately. Categories include the specific failed check names so that different CI failures don't trip the breaker.
Merge conflict retries are exempt from the max attempts limit and circuit breaker because resolving conflicts can be an ongoing process when there is a lot of in-flight work happening on the same repo. Like feedback retries, both attempt and max_attempts are incremented so the attempt number stays unique for log tabbing while keeping the retry budget unchanged.
func (*Store) ScheduleRetry ¶
ScheduleRetry transitions a running task back to pending for another attempt. This is used when the agent hits a retryable error such as Claude rate limits or session max usage exceeded. The task keeps its existing PR/branch info so the next attempt can continue where the previous one left off.
func (*Store) SetAgentStatus ¶
SetAgentStatus stores the structured agent status JSON.
func (*Store) SetCloseReason ¶
SetCloseReason sets the close/failure reason on a task without changing its status.
func (*Store) SetPlanningEpicLister ¶
func (s *Store) SetPlanningEpicLister(lister PlanningEpicLister)
SetPlanningEpicLister sets the PlanningEpicLister used by GetAgentMetrics to include epics that are actively being planned. This is set after construction to avoid circular dependencies.
func (*Store) SetReady ¶
SetReady updates the ready flag on a task. When a task is marked as ready and is pending, a notification is sent so workers can pick it up.
func (*Store) SetRetryContext ¶
SetRetryContext stores detailed failure context (e.g. CI logs) for retries.
func (*Store) SetTaskBranch ¶
SetTaskBranch sets the branch name and moves the task to review status.
func (*Store) SetTaskPullRequest ¶
func (s *Store) SetTaskPullRequest(ctx context.Context, id TaskID, prURL string, prNumber int) error
SetTaskPullRequest sets the PR URL and number, moving the task to review status.
func (*Store) StartOverTask ¶
func (s *Store) StartOverTask(ctx context.Context, id TaskID, params StartOverTaskParams) (*Task, error)
StartOverTask resets a task from review, failed, or closed back to pending, clearing all metadata (logs, PR, branch, agent status, cost) and optionally updating the task details (title, description, acceptance criteria). Returns the task before reset so the caller can close the PR if needed.
func (*Store) StopTask ¶
StopTask transitions a running task back to pending with ready=false, effectively interrupting the worker agent. The task won't be picked up again until the user manually retries it.
func (*Store) StreamTaskLogs ¶
func (s *Store) StreamTaskLogs(ctx context.Context, id TaskID, fn func(attempt int, lines []string) error) error
StreamTaskLogs iterates log batches from the database one row at a time, calling fn for each batch. This avoids loading all logs into memory.
func (*Store) TimeoutStaleTasks ¶
TimeoutStaleTasks fails running tasks whose heartbeat has expired.
func (*Store) Unsubscribe ¶
Unsubscribe removes and closes a subscriber channel.
func (*Store) UpdatePendingTask ¶
func (s *Store) UpdatePendingTask(ctx context.Context, id TaskID, params UpdatePendingTaskParams) error
UpdatePendingTask updates a pending task's editable fields. If the task is no longer in pending status, the update is rejected with a conflict error.
func (*Store) UpdateTaskStatus ¶
UpdateTaskStatus updates a task's status.
func (*Store) WaitForPending ¶
func (s *Store) WaitForPending() <-chan struct{}
WaitForPending returns a channel that signals when a pending task might be available.
type Task ¶
type Task struct {
ID TaskID `json:"id"`
RepoID string `json:"repo_id"`
Title string `json:"title"`
Description string `json:"description"`
Status Status `json:"status"`
Logs []string `json:"logs"`
PullRequestURL string `json:"pull_request_url,omitempty"`
PRNumber int `json:"pr_number,omitempty"`
DependsOn []string `json:"depends_on,omitempty"`
CloseReason string `json:"close_reason,omitempty"`
Attempt int `json:"attempt"`
MaxAttempts int `json:"max_attempts"`
RetryReason string `json:"retry_reason,omitempty"`
AcceptanceCriteria []string `json:"acceptance_criteria"`
AgentStatus string `json:"agent_status,omitempty"`
RetryContext string `json:"retry_context,omitempty"`
ConsecutiveFailures int `json:"consecutive_failures"`
CostUSD float64 `json:"cost_usd"`
MaxCostUSD float64 `json:"max_cost_usd,omitempty"`
SkipPR bool `json:"skip_pr"`
Ready bool `json:"ready"`
EpicID string `json:"epic_id,omitempty"`
Model string `json:"model,omitempty"`
BranchName string `json:"branch_name,omitempty"`
StartedAt *time.Time `json:"started_at,omitempty"`
DurationMs *int64 `json:"duration_ms,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Task represents a unit of work dispatched to an AI coding agent.
func NewTask ¶
func NewTask(repoID, title, description string, dependsOn, acceptanceCriteria []string, maxCostUSD float64, skipPR bool, model string, ready bool) *Task
NewTask creates a new Task with a generated TaskID and pending status.
func (*Task) ComputeDuration ¶
func (t *Task) ComputeDuration()
ComputeDuration calculates the run duration from StartedAt to UpdatedAt for tasks that have finished running (review, merged, closed, failed), or from StartedAt to now for tasks that are currently running.
type TaskID ¶
TaskID is the unique identifier for a Task.
func MustParseTaskID ¶
MustParseTaskID parses a string into a TaskID, panicking on failure.
func ParseTaskID ¶
ParseTaskID parses a string into a TaskID.
type TaskRepository ¶
type TaskRepository interface {
CreateTask(ctx context.Context, task *Task) error
ReadTask(ctx context.Context, id TaskID) (*Task, error)
ListTasks(ctx context.Context) ([]*Task, error)
ListTasksByRepo(ctx context.Context, repoID string) ([]*Task, error)
ListPendingTasks(ctx context.Context) ([]*Task, error)
ListPendingTasksByRepos(ctx context.Context, repoIDs []string) ([]*Task, error)
AppendTaskLogs(ctx context.Context, id TaskID, attempt int, logs []string) error
ReadTaskLogs(ctx context.Context, id TaskID) ([]string, error)
StreamTaskLogs(ctx context.Context, id TaskID, fn func(attempt int, lines []string) error) error
UpdateTaskStatus(ctx context.Context, id TaskID, status Status) error
SetTaskPullRequest(ctx context.Context, id TaskID, prURL string, prNumber int) error
ListTasksInReview(ctx context.Context) ([]*Task, error)
ListTasksInReviewByRepo(ctx context.Context, repoID string) ([]*Task, error)
CloseTask(ctx context.Context, id TaskID, reason string) error
TaskExists(ctx context.Context, id TaskID) (bool, error)
ReadTaskStatus(ctx context.Context, id TaskID) (Status, error)
ClaimTask(ctx context.Context, id TaskID) (bool, error)
HasTasksForRepo(ctx context.Context, repoID string) (bool, error)
// RetryTask atomically transitions a task from review → pending, increments
// attempt, and records the retry reason. Returns false if the task was not
// in review status (already retried or status changed).
RetryTask(ctx context.Context, id TaskID, reason string) (bool, error)
// ScheduleRetryFromRunning atomically transitions a task from running → pending,
// increments attempt, and records the retry reason. Used when the agent hits a
// retryable error (e.g. Claude rate limit or session max usage exceeded).
// Returns false if the task was not in running status.
ScheduleRetryFromRunning(ctx context.Context, id TaskID, reason string) (bool, error)
SetAgentStatus(ctx context.Context, id TaskID, status string) error
SetRetryContext(ctx context.Context, id TaskID, retryCtx string) error
AddCost(ctx context.Context, id TaskID, costUSD float64) error
SetConsecutiveFailures(ctx context.Context, id TaskID, count int) error
SetCloseReason(ctx context.Context, id TaskID, reason string) error
SetBranchName(ctx context.Context, id TaskID, branchName string) error
ListTasksInReviewNoPR(ctx context.Context) ([]*Task, error)
ManualRetryTask(ctx context.Context, id TaskID, instructions string) (bool, error)
// FeedbackRetryTask transitions a task from review → pending and records
// the user's feedback. Unlike ManualRetryTask, it preserves the existing
// PR/branch so the agent pushes fixes to the same branch. The attempt
// counter is reset to 1 so that subsequent automated failure retries get
// a fresh retry budget — failures after user-requested changes are
// caused by those changes, not by the original code.
FeedbackRetryTask(ctx context.Context, id TaskID, feedback string) (bool, error)
DeleteTaskLogs(ctx context.Context, id TaskID) error
RemoveDependency(ctx context.Context, id TaskID, depID string) error
SetReady(ctx context.Context, id TaskID, ready bool) error
// UpdatePendingTask atomically updates a pending task's editable fields.
// Returns false if the task was not in pending status.
UpdatePendingTask(ctx context.Context, id TaskID, params UpdatePendingTaskParams) (bool, error)
// StartOverTask resets a task from review, failed, or closed back to pending with
// fresh metadata. Clears logs, PR, branch, agent status, cost, and retry
// state. Optionally updates title, description, and acceptance criteria.
// Returns false if the task was not in review, failed, or closed status.
StartOverTask(ctx context.Context, id TaskID, params StartOverTaskParams) (bool, error)
// StopTask atomically transitions a task from running → pending with ready=false,
// recording the stop reason. Returns false if the task was not in running status.
StopTask(ctx context.Context, id TaskID, reason string) (bool, error)
// Heartbeat updates the last heartbeat time for a running task.
// Returns true if the task is still running (row was updated), false if the
// task no longer exists or is no longer in running status (e.g. stopped,
// closed, or deleted).
Heartbeat(ctx context.Context, id TaskID) (bool, error)
// ListStaleTasks returns running tasks whose last heartbeat is before the given time.
ListStaleTasks(ctx context.Context, before time.Time) ([]*Task, error)
DeleteTask(ctx context.Context, id TaskID) error
// ListTasksByEpic returns all tasks belonging to a given epic.
ListTasksByEpic(ctx context.Context, epicID string) ([]*Task, error)
// BulkCloseTasksByEpic closes all non-terminal tasks for an epic.
BulkCloseTasksByEpic(ctx context.Context, epicID, reason string) error
// ClearEpicIDForTasks removes the epic_id FK from all tasks for a given epic.
ClearEpicIDForTasks(ctx context.Context, epicID string) error
// BulkDeleteTasksByEpic deletes all tasks (and their logs) for a given epic.
BulkDeleteTasksByEpic(ctx context.Context, epicID string) error
// BulkDeleteTasksByIDs deletes tasks (and their logs) by their IDs.
BulkDeleteTasksByIDs(ctx context.Context, ids []string) error
// DeleteExpiredLogs deletes all log entries older than the given time.
// Returns the number of log batches deleted.
DeleteExpiredLogs(ctx context.Context, before time.Time) (int64, error)
}
TaskRepository defines the data access methods for Tasks.
type UpdatePendingTaskParams ¶
type UpdatePendingTaskParams struct {
Title string
Description string
DependsOn []string
AcceptanceCriteria []string
MaxCostUSD float64
SkipPR bool
Model string
Ready bool
}
UpdatePendingTaskParams holds the fields that can be updated on a pending task. All fields are required — the caller should merge with current values before calling.