Task Lifecycle

Every task in Optio flows through a state machine. Understanding the states and transitions is key to understanding how Optio drives tasks to completion.

States

StateDescription
pendingTask created, not yet queued
waiting_on_depsBlocked by dependency tasks
queuedIn the job queue, waiting for capacity
provisioningFinding or creating a repo pod
runningAgent is actively writing code
needs_attentionCI failed or review requested changes — agent will be resumed
pr_openedPR is open, being monitored by the PR watcher
completedPR merged and issue closed
failedTask failed (can be retried)
cancelledManually cancelled

The Feedback Loop

The feedback loop is what makes Optio more than a simple agent runner. Once a PR is opened, the PR watcher polls every 30 seconds and automatically responds to events:

CI fails

Task transitions to needs_attention, then is re-queued. The agent is resumed with the CI failure output as context.

Review requests changes

If autoResumeOnReview is enabled, the review comments become the agent's next prompt. The agent pushes a fix.

Merge conflicts

The agent is resumed to rebase and resolve conflicts.

CI passes + review approved

If autoMerge is enabled, the PR is squash-merged and the linked issue is closed.

PR closed without merge

Task transitions to failed.

PR merged externally

Task transitions to completed.

How a Task Runs

Here's the detailed flow when a task is processed:

  1. User creates a task via the UI, GitHub Issue assignment, or Linear ticket
  2. Task is inserted and transitions pending → queued, added to BullMQ with priority
  3. Task worker picks up the job and checks concurrency limits (global + per-repo)
  4. Prompt template is rendered with task variables ({{TASK_FILE}}, {{BRANCH_NAME}}, etc.)
  5. Repo pod is found or created via the repo pool service
  6. Worker execs into the pod: git worktree add, writes task file, runs the agent
  7. Structured logs (NDJSON) are streamed back and parsed in real time
  8. Agent opens a PR, cost is recorded, task transitions to pr_opened
  9. PR watcher takes over — polling CI, reviews, and merge status
  10. On merge: completed. On failure: needs_attention → queued (retry)

Priority Queue & Concurrency

Tasks have an integer priority (lower = higher priority). The task worker enforces two concurrency limits:

  • Global limit OPTIO_MAX_CONCURRENT (default 5) — total running tasks across all repos
  • Per-repo limit maxConcurrentTasks (default 2) — tasks per repo pod

When a limit is hit, the task is re-queued with a 10-second delay. Task ordering can be changed via the dashboard or the reorder API.

Tip

You can retry all failed tasks at once with POST /api/tasks/bulk/retry-failed or cancel all active tasks with POST /api/tasks/bulk/cancel-active.

Code Review Agent

Optio can automatically launch a review agent as a subtask of the original coding task:

  • Triggered by the PR watcher (on CI pass or PR open) or manually
  • Runs with a separate review-specific prompt and model (often a cheaper model)
  • The parent task waits for the review subtask to complete before advancing
  • Configurable per repo via reviewEnabled, reviewTrigger, and reviewModel

Worktree Lifecycle

Each task tracks its worktree state for cleanup and retry decisions:

StateMeaning
activeWorktree is in use by a running agent
dirtyAgent finished but worktree not yet cleaned up
resetWorktree was reset for a retry on the same pod
preservedKept for manual inspection or resume
removedWorktree has been cleaned up

Retries reuse the existing worktree on the same pod (reset instead of recreate) for faster restarts, enabled by lastPodId affinity tracking.