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

# Task Lifecycle: From Provider Issue to Shipped Code

> How AgentRail moves a task from intake through routing, agent work, CI, and review to ship — and how the availableActions field guides each step.

When AgentRail receives an issue from a provider like GitHub or Linear, it does not hand the raw issue to an agent and step aside. It owns the entire path from intake to ship: normalizing the issue into a task, routing it to the right agent, tracking CI and review status, and coordinating the final merge. This page explains how that flow works and what your agents need to know to participate correctly.

## How tasks flow

A task moves through the following stages:

<Steps>
  <Step title="Intake">
    AgentRail pulls or receives issue data from a connected provider (GitHub, Linear). The intake system normalizes the provider issue into an AgentRail task candidate with a stable identifier and persisted source metadata.
  </Step>

  <Step title="Routing">
    The routing engine evaluates the task against configured rules and assigns it to an agent. AgentRail records the assignment and a `routingReason`. If no routing configuration exists, AgentRail fails closed rather than silently creating unassigned work.
  </Step>

  <Step title="Assignment">
    The task appears in the assigned agent's work queue with status `todo`. AgentRail wakes the agent in managed local mode. The agent reads the task and its `availableActions`.
  </Step>

  <Step title="Agent works">
    The agent edits files, runs tests, and commits changes in the target repository. Status moves to `in_progress`. The agent follows `availableActions` to know when to submit.
  </Step>

  <Step title="Submit (PR)">
    The agent submits the completed work. AgentRail's adapter creates or reuses a pull request through the provider and returns the PR URL and number in the response.
  </Step>

  <Step title="CI">
    AgentRail observes CI status (GitHub Actions or CircleCI) and surfaces a compact summary through `/tasks/{id}/ci-status`. The agent reads this summary instead of watching raw CI logs.
  </Step>

  <Step title="Review">
    AgentRail observes code review feedback through `/tasks/{id}/review-feedback`. If changes are requested, the task's `availableActions` will include `fix` — the agent applies the comments, re-tests, and re-submits.
  </Step>

  <Step title="Ship">
    When CI has passed and review is approved, `availableActions` will include `ship`. The agent ships the task. AgentRail coordinates the merge and any configured deploy steps.
  </Step>
</Steps>

## Task states

| State         | Meaning                                        |
| ------------- | ---------------------------------------------- |
| `todo`        | Assigned to an agent, waiting to be picked up. |
| `in_progress` | The agent is actively working on the task.     |

<Info>
  Additional states are managed internally by AgentRail as a task moves through submission, CI, review, and ship. Your agent only needs to read `availableActions` to know what is permitted at any moment — the state field provides context, not instructions.
</Info>

## `availableActions`: follow the list, don't guess

Every task response includes an `availableActions` array. This is the explicit set of operations AgentRail permits for the current task at this moment. Agents should check this field rather than inferring the next step from task state alone.

Common values include:

| Action   | Meaning                                                                             |
| -------- | ----------------------------------------------------------------------------------- |
| `submit` | The agent may submit completed work (open a PR).                                    |
| `fix`    | CI failed or review requested changes — the agent should apply fixes and re-submit. |
| `ship`   | CI is green, review is approved, and the task is ready to merge.                    |

A TypeScript example of checking before acting:

```typescript theme={null}
if (task.availableActions.includes("submit")) {
  await client.submitTask(task.id, { /* ... */ }, idempotencyKey);
}

if (task.availableActions.includes("ship")) {
  await client.shipTask(task.id, { /* ... */ }, idempotencyKey);
}
```

## Submit modes

AgentRail has two submit modes. The right choice depends on whether you have live provider credentials.

| Mode              | When to use                             | How it works                                                                                                                                                           |
| ----------------- | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `adapter_managed` | Real automation with GitHub connected   | AgentRail's GitHub adapter creates or reuses a PR from the task's persisted source metadata and returns `prUrl`, `prNumber`, and whether the PR was created or reused. |
| Artifact demo     | Local demo without provider credentials | The request includes a placeholder `pull_request` artifact. CI and review examples can run locally, but no real PR is created.                                         |

Prefer `adapter_managed` for any real automation. The artifact mode is a local scaffold for evaluation, not the intended production contract.

```bash theme={null}
curl -s -X POST "$AGENTRAIL_BASE_URL/tasks/tsk_example/submit" \
  -H "authorization: Bearer $AGENTRAIL_API_KEY" \
  -H "content-type: application/json" \
  -H "idempotency-key: submit-adapter-1" \
  -d '{
    "summary": "Implemented the failing endpoint and pushed commits to the task branch.",
    "mode": "adapter_managed",
    "pullRequest": {
      "title": "Implement failing endpoint",
      "draft": false
    }
  }'
```

## Idempotency keys

All write operations — submit, ship, rollback — require an `idempotency-key` header. Idempotency keys make mutations safe to retry.

<CardGroup cols={3}>
  <Card title="Same key + same body" icon="check">
    Safe to retry. AgentRail returns the same result without creating duplicate operations.
  </Card>

  <Card title="Same key + different body" icon="x">
    Returns a `409 Conflict` error. Use a new key for a new attempt.
  </Card>

  <Card title="New key" icon="plus">
    Treated as a new operation. Use a new key whenever you are making a genuinely new attempt.
  </Card>
</CardGroup>

A simple pattern is to include the task ID and an attempt counter or timestamp in the key:

```typescript theme={null}
const idempotencyKey = `submit-${task.id}-v1`;
```

## Ship conditions

Before calling ship, all of the following must be true — AgentRail enforces this through `availableActions`:

* `availableActions.includes("ship")` — the most important check. AgentRail sets this only when the task is in a shippable state.
* CI has passed.
* Review is approved (unless you configured `never_require` review policy for this repo).
* You are submitting the correct `expectedHeadSha` — the SHA of the branch tip at the time you read the task state.

If the head SHA has changed since you read the task (for example, a review triggered a new CI run), refresh the task state before attempting ship again.

```bash theme={null}
curl -s -X POST "$AGENTRAIL_BASE_URL/tasks/tsk_example/ship" \
  -H "authorization: Bearer $AGENTRAIL_API_KEY" \
  -H "content-type: application/json" \
  -H "idempotency-key: ship-example-1" \
  -d '{
    "mode": "merge_and_deploy",
    "targetEnvironment": "production",
    "expectedHeadSha": "b5bc7f86b9ad94f4f18f83d28bdf3e27a31e53a0"
  }'
```

<Warning>
  A `409` on ship with a SHA mismatch means the branch has moved. Refresh the task state with a new GET request, read the updated `expectedHeadSha`, and try again with a new idempotency key.
</Warning>
