> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orq.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Loops

> Start factory sessions from GitHub, schedules and webhooks, with queueing, rate limits, per-run budgets and pull-request reviews.

Beta

> [!NOTE]
>
> **Agent Sessions** is in private preview. The feature is enabled per workspace by the **Orq.ai** team and the API is not part of the public SDKs yet. Behavior and field names can still change.

A loop binds a trigger to a factory: when the trigger fires, the loop renders its prompt template and starts (or continues) an agent session in that factory. Manage loops under **Factories** > the factory > **Loops**.

## Triggers and actions

| Field | Purpose |
| - | - |
| `trigger.provider` | `github`, `slack`, `schedule` or `webhook`. |
| `trigger.event` | Provider event such as `pull_request.opened`, `issues.labeled`, `Issue.create`, or a cron expression for `schedule`. |
| `trigger.filter` | Optional matchers: `label`, `repository`, `action`, `conclusion`, `cron`. |
| `action.mode` | `new_session` starts a session per run; `continue_session` reuses the newest ready or paused session of the loop. |
| `action.prompt_template` | Prompt with `{{title}}`, `{{body}}`, `{{url}}`, `{{number}}`, `{{repository}}`, `{{ref}}`, `{{labels}}`, `{{sender}}`, `{{action}}`, `{{event}}` plus the triage variables `{{issue_type}}`, `{{priority}}`, `{{owner}}`, `{{route}}`, `{{duplicate_of}}`. |
| `action.open_pr` | Opens a pull request from the session workspace after a successful run and comments on the source issue. |
| `action.post_review` | Posts the agent's structured findings as a pull-request review (see [Pull-request reviews](#pull-request-reviews)). |
| `action.auto_fix` | After a posted review with findings, continues the session to apply the fixes and pushes a commit to the pull-request branch. |

GitHub events reach the platform through the GitHub App webhook. `POST /v2/loops/{loop_id}/trigger` fires a loop manually with caller-supplied variables, which is also how the generic webhook adapter works.

Repository tokens come from the GitHub App installation on the factory's connection. Write access asks for `contents: write` and `pull_requests: write`, plus `issues: write` once the installation has accepted it; without it the agent cannot comment on issues. When the App asks for a permission the installation has not accepted, **Integrations** shows **Accept the App's new permissions on GitHub**, and the connection's menu links to the page on GitHub where its owner accepts it.

## Runs, queue and limits

Every invocation is recorded as an **loop run**. A run moves through `queued` → `running` → `completed` or `failed`, or is recorded as `skipped` without a session.

`Loop.limits` controls how invocations turn into sessions:

| Limit | Default | Behavior |
| - | - | - |
| `max_concurrent_runs` | `1` | Runs above this number wait in the queue. The queue is drained oldest-first whenever a run finishes and on a periodic sweep (about once a minute), so at most this many runs are admitted at the same time. |
| `max_invocations_per_hour` | `20` | Counted over a rolling hour across queued, running, completed and failed runs. Invocations above the cap are recorded as `skipped` with `skip_reason: rate_limited` and never create a session. |
| `run_budget_usd` | `0` (none) | Creates a one-time `API_KEY`-scoped budget of that amount on the session key of each run, so the gateway stops the run's model calls at the cap. `continue_session` runs keep the budget of the reused session. |
| `policy_profile_id` | unset | A [policy profile](https://docs.orq.ai/ai-studio/ai-engineering/agent-sessions/policy-profiles) applied after the workspace and factory profiles as a mandatory ceiling for sessions this loop starts. It can only tighten agents, models, templates, repositories, connections, hours, approvals and repository-config trust; egress stays a factory-level network policy. |

Disabling a loop leaves its queued runs waiting until it is enabled again; deleting it fails them. A run whose session never starts within 40 minutes, or whose session run ended without the control plane noticing, is settled by the reconcile sweep.

The **Activity** view under the loop lists queued, running, completed, failed and skipped runs with their linked sessions and posted reviews; the loop row shows how many runs are queued and running and a 30-day sparkline of daily invocations. `GET /v3/factories/{factory_id}/loops/activity` returns the same counts per loop.

## Pull-request reviews

The **Code review** and **Security audit** templates set `action.post_review`. For such loops the run prompt is extended with an output contract, and when the repository contains a `REVIEW.md` at its root (read at the pull request's head ref), its content is added to the prompt as the repository's review guidelines.

The agent ends its final message with a JSON block:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "summary": "One paragraph verdict.",
  "findings": [
    {
      "severity": "high",
      "confidence": 0.9,
      "cwe": "CWE-79",
      "file": "src/render.ts",
      "line": 42,
      "rationale": "User input is interpolated into HTML without escaping.",
      "suggestion": "Escape the value or use the template helper."
    }
  ]
}
```

| Field | Meaning |
| - | - |
| `severity` | `critical`, `high`, `medium`, `low` or `info`; unknown values become `medium`. |
| `confidence` | 0–1 (percentages are accepted). |
| `cwe` | Optional CWE identifier for weaknesses. |
| `file`, `line` | Path relative to the repository root and the line in the pull request's version of the file. |
| `rationale`, `suggestion` | Why it matters and the concrete fix. |

The block is parsed leniently (last fenced JSON block, bare object or bare array). Findings are stored on the run and posted as one pull-request review through the GitHub App: findings with a file and line become inline comments, the rest go into the review body, and when GitHub rejects a line outside the diff the review is re-posted with every finding folded into the body. Free-text final messages without a JSON block are posted as the review summary.

With `action.auto_fix`, a review with at least one finding above `info` continues the same session with the findings to fix; when that run completes, the platform commits the workspace and pushes `fix: apply review findings` to the pull-request branch (same-repository branches only). The review URL and fix commit appear on the run. Merging stays a human decision.

Reviews require a GitHub repository credential from the GitHub App installation on the factory's connection. GitLab merge-request discussions are not supported yet; loops that post reviews on GitLab repositories fail with an explanatory error.

## API

| Method and path | Purpose |
| - | - |
| `POST /v3/factories/{factory_id}/loops` | Create a loop (`limits` optional; defaults apply). |
| `GET /v3/factories/{factory_id}/loops` | List the loops of a factory. |
| `GET /v3/factories/{factory_id}/loops/activity` | Queue depth, running and outcome counts, daily invocations per loop. |
| `PATCH /v2/loops/{loop_id}` | Update display name, trigger, action, visibility, enabled or limits. |
| `POST /v2/loops/{loop_id}/trigger` | Fire the loop; the response carries the recorded run (`running`, `queued` or `skipped`). |
| `GET /v2/loops/{loop_id}/runs` | List runs with sessions, errors and reviews, newest first. |
| `DELETE /v2/loops/{loop_id}` | Delete the loop and fail its queued runs. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.