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

# Task Lifecycle

> Understand how agent tasks move through states — from creation to completion — and how to track, stream, continue, or cancel them.

Every agent task follows a predictable lifecycle. This page explains each phase, the available status values, and the patterns you can use to interact with a task at each stage.

<Note>
  The lifecycle, status values, and event stream below are **identical across [agent runtimes](/api-reference/v1/agent-runtimes)** — a Codex task and a Claude task move through the same states and emit the same events. Whichever runtime the `model` (or `agent` override) selects is transparent to every endpoint on this page.
</Note>

## Lifecycle Overview

```
POST /api/v1/tasks
        │
        ▼
   { taskId, runId }          ← created (status: queued)
        │
        ▼
   Agent starts               ← status: running
        │
        ├──► GET  /api/v1/tasks/:id/status          poll lightweight status
        │
        ├──► GET  /api/v1/tasks/:id/logs/stream     live SSE log stream
        │
        ├──► GET  /api/v1/agent/stream?runId=...    raw SSE stream
        │
        ├──► POST /api/v1/tasks/:id/continue        send a follow-up prompt
        │
        └──► PATCH /api/v1/tasks/:id               cancel the task
                │
                ▼
        Terminal state         ← completed | failed | cancelled | interrupted
```

## Status Values

| Status        | Description                                 | Terminal? |
| ------------- | ------------------------------------------- | --------- |
| `queued`      | Task is waiting to be picked up by an agent | No        |
| `running`     | Agent is actively executing the task        | No        |
| `completed`   | Task finished successfully                  | ✅ Yes     |
| `failed`      | Task encountered an unrecoverable error     | ✅ Yes     |
| `cancelled`   | Task was cancelled by the user              | ✅ Yes     |
| `interrupted` | Task was interrupted (e.g. server restart)  | ✅ Yes     |

Once a task reaches a terminal state it will not change again. Poll until you see one of the four terminal statuses.

## Phase 1 — Create

Start a task with `POST /api/v1/tasks`. You receive a `runId` immediately — the agent begins executing asynchronously.

```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
curl -X POST 'https://agent.blackbox.ai/api/v1/tasks' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "prompt": "Add a README in French",
    "repoUrl": "https://github.com/org/repo.git",
    "selectedBranch": "main"
  }'
```

```json theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
{
  "taskId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "runId":  "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "chatId": "chat_def789ghi012",
  "agentCount": 1
}
```

Save the `runId` — you'll use it for every subsequent operation.

## Phase 2 — Monitor

You have two options for tracking progress:

### Option A — Poll Status (lightweight)

Best for simple integrations. Call `GET /api/v1/tasks/:id/status` every few seconds:

```javascript theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
const DONE = ["completed", "failed", "cancelled", "interrupted"];

while (true) {
  const res = await fetch(`/api/v1/tasks/${runId}/status`, {
    headers: { Authorization: `Bearer ${API_KEY}` },
  });
  const s = await res.json();

  console.log(`${s.status} — ${s.progress}%`);
  if (DONE.includes(s.status)) break;

  await new Promise(r => setTimeout(r, 3000));
}
```

The `progress` field (0–100) is a linear estimate based on elapsed time.

### Option B — Stream Logs (real-time)

Best for live UIs or CLI output. Connect to the SSE stream and receive events as they happen:

```javascript theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
const response = await fetch(`/api/v1/tasks/${runId}/logs/stream`, {
  headers: { Authorization: `Bearer ${API_KEY}` },
});

const reader = response.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;

  for (const line of decoder.decode(value).split("\n")) {
    if (!line.startsWith("data: ")) continue;
    const event = JSON.parse(line.slice(6));

    if (event.type === "text-delta")   process.stdout.write(event.delta);
    if (event.type === "tool-call-start") console.log(`\nTool: ${event.toolName}`);
    if (event.type === "finish")       { console.log(`\nDone: ${event.status}`); break; }
  }
}
```

## Phase 3 — Retrieve Results

Once completed, fetch the full task details including the conversation history and GitHub context:

```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
curl 'https://agent.blackbox.ai/api/v1/tasks/RUN_ID' \
  -H 'Authorization: Bearer YOUR_API_KEY'
```

Key fields in the response:

| Field                  | Description                        |
| ---------------------- | ---------------------------------- |
| `status`               | Final status of the run            |
| `github.createdBranch` | Branch the agent pushed changes to |
| `messages`             | Full conversation history          |
| `completedAt`          | ISO 8601 timestamp of completion   |

Extract the agent's reply:

```javascript theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
const data = await res.json();
const lastReply = data.messages.filter(m => m.role === "assistant").at(-1);
const text = lastReply?.parts?.find(p => p.type === "text")?.text ?? "";
console.log("Agent reply:", text);
```

## Phase 4 — Continue (Optional)

Send a follow-up prompt to the same task. The agent receives the full conversation history as context and, if a GitHub repo was involved, continues from the branch it created:

```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
curl -X POST 'https://agent.blackbox.ai/api/v1/tasks/RUN_ID/continue' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{ "prompt": "Now add unit tests for the new module" }'
```

The response contains a **new** `runId` for the follow-up run. Use it to track the continuation independently.

## Cancel a Running Task

Send a `PATCH` request with `action: "cancel"` at any point while the task is `queued` or `running`:

```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
curl -X PATCH 'https://agent.blackbox.ai/api/v1/tasks/RUN_ID' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{ "action": "cancel" }'
```

```json theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
{ "success": true, "status": "cancelled", "message": "Task cancelled successfully" }
```

Cancelling a task that is already in a terminal state returns `success: false`.

## Multi-Agent Tasks

When you pass `selectedAgents` with 2–5 entries, each agent gets its own `runId`. Track each run independently using the same endpoints described above.

## Recommended Patterns

### Simple — Poll with Backoff

```javascript theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
async function pollWithBackoff(runId, apiKey) {
  const DONE = ["completed", "failed", "cancelled", "interrupted"];
  let delay = 1000;

  while (true) {
    const res = await fetch(`/api/v1/tasks/${runId}/status`, {
      headers: { Authorization: `Bearer ${apiKey}` },
    });
    const s = await res.json();
    if (DONE.includes(s.status)) return s;

    await new Promise(r => setTimeout(r, delay));
    delay = Math.min(delay * 2, 30_000); // cap at 30s
  }
}
```

### Advanced — Stream + Continue

```javascript theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
// 1. Create task
const res = await fetch("/api/v1/tasks", {
  method: "POST",
  headers: { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({ prompt: "Build a REST API" }),
});
const { runId } = await res.json();

// 2. Stream live output
const stream = await fetch(`/api/v1/tasks/${runId}/logs/stream`, {
  headers: { Authorization: `Bearer ${API_KEY}` },
});
const reader = stream.body.getReader();
const decoder = new TextDecoder();
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  for (const line of decoder.decode(value).split("\n")) {
    if (!line.startsWith("data: ")) continue;
    const event = JSON.parse(line.slice(6));
    if (event.type === "text-delta") process.stdout.write(event.delta);
    if (event.type === "finish") break;
  }
}

// 3. Continue with a follow-up
const cont = await fetch(`/api/v1/tasks/${runId}/continue`, {
  method: "POST",
  headers: { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({ prompt: "Now add OpenAPI docs" }),
});
const { runId: newRunId } = await cont.json();
```

## Related Endpoints

<CardGroup cols={2}>
  <Card title="Create Task" href="/api-reference/v1/create-task">
    `POST /api/v1/tasks`
  </Card>

  <Card title="Get Task Status" href="/api-reference/v1/task-status">
    `GET /api/v1/tasks/:id/status`
  </Card>

  <Card title="Stream Task Logs" href="/api-reference/v1/stream-logs">
    `GET /api/v1/tasks/:id/logs/stream`
  </Card>

  <Card title="Continue Task" href="/api-reference/v1/continue-task">
    `POST /api/v1/tasks/:id/continue`
  </Card>

  <Card title="Get Task" href="/api-reference/v1/get-task">
    `GET /api/v1/tasks/:id`
  </Card>

  <Card title="Cancel Task" href="/api-reference/v1/cancel-task">
    `PATCH /api/v1/tasks/:id`
  </Card>
</CardGroup>
