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
| State | Description |
|---|---|
| pending | Task created, not yet queued |
| waiting_on_deps | Blocked by dependency tasks |
| queued | In the job queue, waiting for capacity |
| provisioning | Finding or creating a repo pod |
| running | Agent is actively writing code |
| needs_attention | CI failed or review requested changes — agent will be resumed |
| pr_opened | PR is open, being monitored by the PR watcher |
| completed | PR merged and issue closed |
| failed | Task failed (can be retried) |
| cancelled | Manually 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:
- User creates a task via the UI, GitHub Issue assignment, or Linear ticket
- Task is inserted and transitions
pending → queued, added to BullMQ with priority - Task worker picks up the job and checks concurrency limits (global + per-repo)
- Prompt template is rendered with task variables (
{{TASK_FILE}},{{BRANCH_NAME}}, etc.) - Repo pod is found or created via the repo pool service
- Worker execs into the pod:
git worktree add, writes task file, runs the agent - Structured logs (NDJSON) are streamed back and parsed in real time
- Agent opens a PR, cost is recorded, task transitions to
pr_opened - PR watcher takes over — polling CI, reviews, and merge status
- 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
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, andreviewModel
Worktree Lifecycle
Each task tracks its worktree state for cleanup and retry decisions:
| State | Meaning |
|---|---|
| active | Worktree is in use by a running agent |
| dirty | Agent finished but worktree not yet cleaned up |
| reset | Worktree was reset for a retry on the same pod |
| preserved | Kept for manual inspection or resume |
| removed | Worktree 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.