---
title: Pipelines
description: "Orchestrate multi-step agent workflows with DAG-based execution."
---

# Pipelines

Pipelines enable durable, multi-step workflow orchestration. Each pipeline is a DAG (Directed Acyclic Graph) of stages that execute commands, await human approvals, or evaluate gates.

## Create Pipeline

```bash
curl -X POST https://api.caged.dev/v1/pipelines \
  -H "Authorization: Bearer caged_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "deploy-to-prod",
    "description": "Build, test, and deploy to production",
    "stages": [
      {
        "name": "build",
        "type": "command",
        "command": "npm run build",
        "timeout": "5m"
      },
      {
        "name": "test",
        "type": "command",
        "command": "npm test",
        "depends_on": ["build"]
      },
      {
        "name": "approve-deploy",
        "type": "await_approval",
        "config": {
          "message": "Approve deployment to production?",
          "channels": ["slack", "dashboard"],
          "sla_timeout": "30m"
        },
        "depends_on": ["test"]
      },
      {
        "name": "deploy",
        "type": "command",
        "command": "npm run deploy",
        "depends_on": ["approve-deploy"]
      }
    ],
    "defaults": {
      "template": "node-20",
      "on_failure": "stop",
      "retry": {
        "max_attempts": 2,
        "backoff": "5s"
      }
    }
  }'
```

**Response** `201 Created`

```json
{
  "id": "pipe-a1b2c3d4",
  "account_id": "acc-x1y2z3",
  "name": "deploy-to-prod",
  "description": "Build, test, and deploy to production",
  "status": "active",
  "version": 1,
  "stages": [...],
  "defaults": {...},
  "created_at": "2026-08-02T10:00:00Z",
  "updated_at": "2026-08-02T10:00:00Z"
}
```

## List Pipelines

```bash
curl https://api.caged.dev/v1/pipelines \
  -H "Authorization: Bearer caged_sk_..."
```

**Response** `200 OK`

```json
[
  {
    "id": "pipe-a1b2c3d4",
    "name": "deploy-to-prod",
    "status": "active",
    "version": 1,
    "created_at": "2026-08-02T10:00:00Z"
  }
]
```

## Get Pipeline

```bash
curl https://api.caged.dev/v1/pipelines/pipe-a1b2c3d4 \
  -H "Authorization: Bearer caged_sk_..."
```

Returns the full pipeline definition.

## Delete Pipeline

Archives a pipeline (soft delete). Existing runs are preserved.

```bash
curl -X DELETE https://api.caged.dev/v1/pipelines/pipe-a1b2c3d4 \
  -H "Authorization: Bearer caged_sk_..."
```

**Response** `204 No Content`

---

## Start Run

Trigger a new execution of a pipeline.

```bash
curl -X POST https://api.caged.dev/v1/pipelines/pipe-a1b2c3d4/runs \
  -H "Authorization: Bearer caged_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "trigger": "api",
    "env": {
      "NODE_ENV": "production",
      "DEPLOY_TARGET": "us-east-1"
    },
    "repo": "https://github.com/myorg/myapp",
    "branch": "main"
  }'
```

**Response** `201 Created`

```json
{
  "id": "run-e5f6g7h8",
  "pipeline_id": "pipe-a1b2c3d4",
  "pipeline_name": "deploy-to-prod",
  "status": "pending",
  "trigger": "api",
  "input": {
    "env": {"NODE_ENV": "production", "DEPLOY_TARGET": "us-east-1"},
    "repo": "https://github.com/myorg/myapp",
    "branch": "main"
  },
  "created_at": "2026-08-02T10:05:00Z"
}
```

## List Runs

```bash
curl https://api.caged.dev/v1/pipelines/pipe-a1b2c3d4/runs \
  -H "Authorization: Bearer caged_sk_..."
```

Query params: `limit` (default 20), `offset` (default 0).

**Response** `200 OK`

```json
[
  {
    "id": "run-e5f6g7h8",
    "pipeline_id": "pipe-a1b2c3d4",
    "pipeline_name": "deploy-to-prod",
    "status": "running",
    "trigger": "api",
    "started_at": "2026-08-02T10:05:00Z",
    "duration_ms": 45000
  }
]
```

## Get Run

```bash
curl https://api.caged.dev/v1/pipelines/pipe-a1b2c3d4/runs/run-e5f6g7h8 \
  -H "Authorization: Bearer caged_sk_..."
```

Returns full run details including all stage statuses.

## Cancel Run

```bash
curl -X POST https://api.caged.dev/v1/pipelines/pipe-a1b2c3d4/runs/run-e5f6g7h8/cancel \
  -H "Authorization: Bearer caged_sk_..."
```

**Response** `204 No Content`

---

## Run State

Pipeline runs include a key/value state store for sharing data between stages. State is scoped to the run — no cross-pipeline or cross-run leakage.

### List Run State

Retrieve all state entries for a run.

```bash
curl https://api.caged.dev/v1/pipelines/pipe-a1b2c3d4/runs/run-e5f6g7h8/state \
  -H "Authorization: Bearer caged_sk_..."
```

**Response** `200 OK`

```json
[
  {
    "key": "build.artifact",
    "value": "s3://caged-artifacts/run-e5f6g7h8/app.zip",
    "type": "string",
    "mime_type": "",
    "size_bytes": 52,
    "created_by": "build",
    "created_at": "2026-08-02T10:06:00Z",
    "expires_at": "2026-08-09T10:06:00Z"
  },
  {
    "key": "analysis_results",
    "value": "{\"files\": [\"src/main.ts\"], \"score\": 85}",
    "type": "json",
    "mime_type": "application/json",
    "size_bytes": 42,
    "created_by": "analyze",
    "created_at": "2026-08-02T10:05:30Z",
    "expires_at": "2026-08-09T10:05:30Z"
  }
]
```

### Get State Entry

Retrieve a single state entry by key.

```bash
curl https://api.caged.dev/v1/pipelines/pipe-a1b2c3d4/runs/run-e5f6g7h8/state/analysis_results \
  -H "Authorization: Bearer caged_sk_..."
```

**Response** `200 OK`

```json
{
  "key": "analysis_results",
  "value": "{\"files\": [\"src/main.ts\"], \"score\": 85}",
  "type": "json",
  "mime_type": "application/json",
  "size_bytes": 42,
  "created_by": "analyze",
  "created_at": "2026-08-02T10:05:30Z",
  "expires_at": "2026-08-09T10:05:30Z"
}
```

**Response** `404 Not Found` if key doesn't exist.

### Set State Entry

Create or update a state entry.

```bash
curl -X PUT https://api.caged.dev/v1/pipelines/pipe-a1b2c3d4/runs/run-e5f6g7h8/state/my_key \
  -H "Authorization: Bearer caged_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "value": {"status": "complete", "items": 42},
    "type": "json",
    "mime_type": "application/json",
    "created_by": "api",
    "ttl_seconds": 86400
  }'
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `value` | any | Yes | The value to store (string or JSON object) |
| `type` | string | No | `string`, `json`, `file`, `patch`, `artifact` (default: `string`) |
| `mime_type` | string | No | MIME type for binary/file types |
| `created_by` | string | No | Identifier for the creator (stage name, `api`, etc.) |
| `ttl_seconds` | integer | No | Time-to-live in seconds (default: 604800 = 7 days, max: 2592000 = 30 days) |

**Response** `200 OK`

```json
{
  "key": "my_key",
  "value": "{\"status\": \"complete\", \"items\": 42}",
  "type": "json",
  "mime_type": "application/json",
  "size_bytes": 35,
  "created_by": "api",
  "created_at": "2026-08-02T10:10:00Z",
  "expires_at": "2026-08-03T10:10:00Z"
}
```

**Validation Errors** `400 Bad Request`:

- Key exceeds 256 characters
- Value exceeds 1 MB
- Run exceeds 100 state entries
- Run exceeds 10 MB total state size
- TTL exceeds 30 days

### Delete State Entry

Remove a state entry.

```bash
curl -X DELETE https://api.caged.dev/v1/pipelines/pipe-a1b2c3d4/runs/run-e5f6g7h8/state/temp_data \
  -H "Authorization: Bearer caged_sk_..."
```

**Response** `204 No Content`

### State Entry Fields

| Field | Type | Description |
|-------|------|-------------|
| `key` | string | Unique key within the run (max 256 chars) |
| `value` | string | Stored value (JSON-serialized for non-string types) |
| `type` | string | Value type: `string`, `json`, `file`, `patch`, `artifact` |
| `mime_type` | string | MIME type (for file/artifact types) |
| `size_bytes` | integer | Size of value in bytes |
| `created_by` | string | Stage name or identifier that created the entry |
| `created_at` | string | ISO 8601 creation timestamp |
| `expires_at` | string | ISO 8601 expiration timestamp |

### State Limits

| Limit | Value |
|-------|-------|
| Max key length | 256 characters |
| Max value size | 1 MB |
| Max entries per run | 100 |
| Max total size per run | 10 MB |
| Default TTL | 7 days |
| Max TTL | 30 days |

---

## Get Run Stages

```bash
curl https://api.caged.dev/v1/pipelines/pipe-a1b2c3d4/runs/run-e5f6g7h8/stages \
  -H "Authorization: Bearer caged_sk_..."
```

**Response** `200 OK`

```json
[
  {
    "id": "stg-i9j0k1l2",
    "name": "build",
    "type": "command",
    "status": "succeeded",
    "attempt": 1,
    "exit_code": 0,
    "duration_ms": 12000,
    "started_at": "2026-08-02T10:05:01Z",
    "completed_at": "2026-08-02T10:05:13Z"
  },
  {
    "id": "stg-m3n4o5p6",
    "name": "test",
    "type": "command",
    "status": "running",
    "attempt": 1,
    "started_at": "2026-08-02T10:05:14Z"
  }
]
```

---

## Pipeline Fields

| Field | Type | Description |
|-------|------|-------------|
| `id` | string | Unique pipeline ID |
| `account_id` | string | Owner account |
| `name` | string | Pipeline name (unique per account) |
| `description` | string | Human-readable description |
| `status` | string | `active` or `archived` |
| `version` | integer | Incremented on each update |
| `stages` | array | Stage definitions (see below) |
| `defaults` | object | Default settings for all stages |

## Stage Definition

| Field | Type | Description |
|-------|------|-------------|
| `name` | string | Unique stage name within pipeline |
| `type` | string | `command`, `await_approval`, `gate`, `eval` |
| `command` | string | Command to execute (for `command` type) |
| `template` | string | Sandbox template (default from pipeline defaults) |
| `timeout` | string | Execution timeout (e.g., "5m", "1h") |
| `retry` | object | Retry policy (`max_attempts`, `backoff`, `max_backoff`) |
| `on_failure` | string | `stop` (default) or `continue` |
| `depends_on` | array | Stage names this stage depends on |
| `condition` | object | Conditional execution rules |
| `env` | object | Environment variables for this stage |
| `config` | object | Type-specific configuration |

## Stage Types

### `command`
Runs a shell command in an isolated sandbox. The sandbox is created, command executed, and sandbox destroyed for each stage.

### `await_approval`
Pauses the run and requests human approval via configured channels (dashboard, Slack, email). The run resumes when approved or is canceled if rejected.

```json
{
  "type": "await_approval",
  "config": {
    "message": "Deploy to production?",
    "channels": ["slack", "dashboard"],
    "sla_timeout": "30m",
    "auto_decision": "reject"
  }
}
```

### `gate`
Evaluates a condition (trust score, cost threshold, custom expression). Passes or fails instantly.

```json
{
  "type": "gate",
  "config": {
    "trust_above": 80,
    "cost_below": 5.00,
    "fail_fast": true
  }
}
```

**Gate Config Fields:**

| Field | Type | Description |
|-------|------|-------------|
| `trust_above` | int | Minimum trust score (0-100) to pass |
| `cost_below` | float | Maximum cost in USD to pass |
| `expression` | string | Custom CEL expression (coming soon) |
| `state_key` | string | State key for dynamic evaluation |
| `fail_fast` | bool | Stop pipeline immediately on failure |

### `eval`
Runs a Cage Eval scenario or suite and evaluates gate conditions. Supports regression detection against historical baselines.

```json
{
  "type": "eval",
  "config": {
    "scenario_name": "code-review",
    "min_pass_rate": 0.9,
    "max_cost_usd": 1.00,
    "fail_on_regression": true,
    "baseline_count": 5,
    "regression_threshold": 0.1
  }
}
```

**Eval Config Fields:**

| Field | Type | Description |
|-------|------|-------------|
| `scenario_id` | UUID | ID of the scenario to run |
| `scenario_name` | string | Name of the scenario (alternative to ID) |
| `suite_id` | UUID | Run all scenarios in a suite |
| `suite_name` | string | Suite name (alternative to ID) |
| `min_pass_rate` | float | Minimum pass rate (0-1) to pass gate |
| `max_cost_usd` | float | Maximum allowed cost for the eval run |
| `fail_on_regression` | bool | Block if score regresses vs baseline |
| `baseline_count` | int | Number of previous runs for baseline (default: 5) |
| `regression_threshold` | float | Max allowed score drop (default: 0.1 = 10%) |
| `store_result_in_state` | bool | Save eval result to pipeline state |
| `result_state_key` | string | State key for result (default: `eval_result`) |

### `a2a`
Delegates work to an external A2A-compatible agent. See [A2A Protocol](/guides/a2a-protocol) for details.

```json
{
  "type": "a2a",
  "config": {
    "agent_url": "https://agent.example.com",
    "skill_id": "code-review",
    "prompt": "Review the PR changes",
    "max_cost_usd": 2.00
  }
}
```

---

## Gate Results

For `eval` and `gate` stages, the stage response includes a `gate_result` field with evaluation details:

```json
{
  "id": "stg-m3n4o5p6",
  "name": "quality-check",
  "type": "eval",
  "status": "failed",
  "gate_result": {
    "passed": false,
    "failed_checks": [
      {
        "type": "min_pass_rate",
        "expected": "0.90",
        "actual": "0.75",
        "passed": false,
        "message": "Pass rate 75.0% below required 90.0%"
      },
      {
        "type": "regression",
        "expected": ">= 85.0% (baseline)",
        "actual": "75.0%",
        "passed": false,
        "message": "Score regressed 11.8% vs baseline (85.0% → 75.0%)"
      }
    ],
    "passed_checks": [
      {
        "type": "max_cost",
        "expected": "< $1.0000",
        "actual": "$0.4500",
        "passed": true
      }
    ],
    "message": "Eval gate failed: 2 check(s) failed",
    "evaluated_at": "2026-08-02T10:15:00Z",
    "score": 0.75,
    "total_cost": 0.45,
    "baseline_score": 0.85,
    "baseline_count": 5,
    "score_delta": -0.10,
    "is_regression": true,
    "regression_pct": 11.8
  }
}
```

**Gate Check Types:**

| Type | Description |
|------|-------------|
| `eval_status` | Eval run status (passed/failed/errored) |
| `min_pass_rate` | Minimum assertion pass rate |
| `max_cost` | Maximum cost threshold |
| `regression` | Score regression vs baseline |
| `trust` | Trust score threshold |
| `cost` | Accumulated cost threshold |
| `expression` | Custom expression evaluation |

## Run Status

| Status | Description |
|--------|-------------|
| `pending` | Created but not yet started |
| `running` | At least one stage is executing |
| `paused` | Waiting for human approval |
| `succeeded` | All stages completed successfully |
| `failed` | A stage failed (no recovery) |
| `canceled` | Manually canceled |

## Stage Status

| Status | Description |
|--------|-------------|
| `pending` | Not yet started |
| `waiting` | Waiting for dependencies |
| `running` | Currently executing |
| `paused_approval` | Waiting for human approval |
| `succeeded` | Completed successfully |
| `failed` | Failed after all retries |
| `skipped` | Skipped due to conditional |
| `canceled` | Run was canceled |
