Skip to main content
Optio is best understood as a CI/CD pipeline where the build step is an AI agent. You submit a task; Optio provisions an environment, runs the agent, tracks the resulting PR through CI and review, and merges when everything passes.

The full picture

You create a task          Optio runs the agent           Optio closes the loop
─────────────────          ──────────────────────         ──────────────────────

  GitHub Issue              Provision repo pod             CI fails?
  Manual task       ──→     Create git worktree    ──→       → Resume agent with failure context
  Linear ticket             Run Claude Code / Codex        Review requests changes?
                            Open a PR                        → Resume agent with feedback
                                                           CI passes + approved?
                                                             → Squash-merge + close issue

Task intake

Tasks enter Optio through one of three channels:
Go to Tasks → New Task and fill in the title, repository, and description. The task is created immediately and enters the queue.You can also create tasks from templates on the Templates page, or set up recurring tasks on the Schedules page.

The task lifecycle

Every task moves through a defined set of states. All transitions are validated — invalid transitions are rejected.
pending → queued → provisioning → running → pr_opened → completed
                                    ↓  ↑        ↓  ↑
                               needs_attention   needs_attention
                                    ↓                ↓
                                 cancelled         cancelled
                               running → failed → queued (retry)
1

Pending → Queued

When you create a task, it enters pending briefly while Optio validates the request, then transitions to queued and a BullMQ job is added with the task’s priority value (lower number = higher priority).If a task has dependencies on other tasks, it enters waiting_on_deps instead of queued and waits until all dependencies complete.
2

Queued → Provisioning

The task worker picks up the job. Before starting, it checks two concurrency limits:
  • Global limit — by default, 5 tasks can run simultaneously across all repositories
  • Per-repo limit — by default, 2 tasks can run concurrently in the same repository’s pod
If either limit is reached, the task is re-queued with a short delay and retried. Once capacity is available, the task moves to provisioning.
3

Provisioning → Running

Optio finds or creates a Kubernetes pod for the target repository — this is the pod-per-repo model described below. Once the pod is ready, Optio execs into it, creates a git worktree for the task’s branch, writes the task description to .optio/task.md, and launches the agent.The task moves to running as soon as the agent process starts.
4

Running → PR Opened

The agent reads the task file, writes code in the isolated worktree, and opens a pull request against the repository’s default branch. Optio streams the agent’s structured JSON output to the dashboard in real time.When a PR URL is detected in the agent output, Optio stores the PR number and transitions the task to pr_opened. The agent process exits — it has done its job.The worktree is cleaned up from the pod.
5

PR monitoring

The PR watcher runs every 30 seconds as a repeating background job. For each task in pr_opened state, it fetches the PR’s current data from GitHub:
  • CI check runs and their statuses
  • Review state (approved, changes requested, pending)
  • PR state (open, merged, closed)
This information is stored on the task and shown in the dashboard’s pipeline timeline.
6

Feedback loop

The PR watcher doesn’t just observe — it acts. Depending on what it finds, it triggers one of several responses:
  • CI failing → transitions task to needs_attention, re-queues it, and resumes the agent with the CI failure output as additional context
  • Merge conflicts → same as CI failure — agent is resumed and asked to rebase
  • Review requests changes → if autoResumeOnReview is enabled for the repo, the review comments are passed to the agent as a resume prompt
  • CI passes → if code review is enabled, a review agent is launched as a subtask
  • PR merged → task transitions to completed, linked issues are closed, cost is recorded
  • PR closed without merge → task transitions to failed
7

Completed

The task is in its terminal state. The PR has been squash-merged, any linked GitHub Issue or Linear ticket has been closed, and the final cost (in USD) has been recorded against the task.You can view the full agent log, cost breakdown, and PR link from the task detail page.

Pod-per-repo architecture

Optio uses a pod-per-repo model rather than creating a new container for every task. This is the central performance optimization. When the first task arrives for a repository:
  1. Optio creates a Kubernetes pod with a persistent volume
  2. The pod clones the repository and runs any .optio/setup.sh setup script present in the repo
  3. The pod then runs sleep infinity — it stays alive waiting for work
When subsequent tasks arrive for the same repository:
  1. Optio execs into the existing pod
  2. Runs git fetch origin && git worktree add to create an isolated branch checkout
  3. Launches the agent in that worktree
  4. Cleans up the worktree when the agent exits
Multiple tasks can run concurrently in the same pod — each in its own worktree, completely isolated from one another. The pod’s persistent volume means installed tools and cached dependencies survive across tasks. Pods idle for 10 minutes after their last task completes, then are automatically cleaned up. The next task for that repo creates a fresh pod.
For repositories with high task volume, you can scale to multiple pod instances per repo and increase the agents-per-pod limit. See the repository configuration docs for maxPodInstances and maxAgentsPerPod.

Code review agent

Optio can automatically run a second AI agent to review the code before merging. The review agent:
  • Is launched as a subtask of the original coding task
  • Runs in the same repo pod, scoped to the PR branch
  • Uses a separate prompt template and can use a different (cheaper) model
  • Posts review comments to the PR
  • Blocks the parent task from advancing until it completes
You can configure the review trigger per repository: launch on PR open, or wait until CI passes first.

Architecture overview

┌──────────────┐     ┌────────────────────┐     ┌───────────────────────────┐
│   Web UI     │────→│    API Server      │────→│      Kubernetes           │
│   Next.js    │     │    Fastify         │     │                           │
│   :3100      │     │                    │     │  ┌── Repo Pod A ───────┐  │
│              │←ws──│  Workers:          │     │  │ clone + sleep       │  │
│  Dashboard   │     │  ├─ Task Queue     │     │  │ ├─ worktree 1  ⚡    │  │
│  Tasks       │     │  ├─ PR Watcher     │     │  │ ├─ worktree 2  ⚡    │  │
│  Repos       │     │  ├─ Health Mon     │     │  │ └─ worktree N  ⚡    │  │
│  Cluster     │     │  └─ Ticket Sync    │     │  └─────────────────────┘  │
│  Costs       │     │                    │     │  ┌── Repo Pod B ───────┐  │
│  Issues      │     │  Services:         │     │  │ clone + sleep       │  │
│              │     │  ├─ Repo Pool      │     │  │ └─ worktree 1  ⚡    │  │
│              │     │  ├─ Review Agent   │     │  └─────────────────────┘  │
│              │     │  └─ Auth/Secrets   │     │                           │
└──────────────┘     └─────────┬──────────┘     └───────────────────────────┘
                               │                  ⚡ = Claude Code / Codex
                        ┌──────┴──────┐
                        │  Postgres   │  Tasks, logs, events, secrets, repos
                        │  Redis      │  Job queue, pub/sub, live streaming
                        └─────────────┘
The web UI communicates with the API over HTTP and WebSocket. The API manages all workers and services. Agent pods run in Kubernetes and are managed entirely by the API — your browser never communicates with them directly. Live log streaming works through Redis pub/sub: the task worker publishes agent output lines to a Redis channel, and the API relays them to browser clients over a WebSocket connection.