# Tasks

Source: https://docs.lookover.ai/webagent/concepts/tasks

> A task is one goal that the browser agent works on in a session. Modes, step limits and why a task stops.

A task is one goal in plain language, for example "log in and open the billing page". The browser agent looks at the page, decides on an action, does it, and repeats until the goal is done or it has to stop. A task runs in a [session](/concepts/sessions).

Start a task with the `run_task` MCP tool. See [Tools](/mcp/tools#run_task). Read stored tasks with `get_task`, or with `GET /v1/sessions/:id/tasks` and `GET /v1/tasks`. Read the report of a task with `get_report`.

## One goal per task [#one-goal-per-task]

Give one task one clear goal. For a flow with several pages (log in, add to cart, pay), run several tasks on the same session: open the session with `create_session` (or give the first `run_task` a `startUrl` and `keepOpen: true`), then call `run_task` once per stage with the same `sessionId`. The browser keeps its cookies and page between tasks.

A goal is at most 2000 characters. The goal and the answer are stored with the task, so do not put secrets in a goal.

## Modes [#modes]

The mode says how much the agent asks you.

| Mode | Behaviour |
|---|---|
| `auto` | Acts alone and asks only when it is stuck. The default |
| `full_auto` | Never asks. At a hard block it stops instead |
| `ask` | Asks before anything that changes state |
| `plan` | Shows a plan and waits for approval |

`run_task` offers only `auto` and `full_auto`. An MCP call cannot answer a question, so a task that waits would sit idle until it ends as `unanswered`.

## Limits of one task [#limits-of-one-task]

- `maxSteps`: 1 to 50. The agent uses 25 when you give none.
- A cost cap per task. The platform sets it, and the engine of the session may set another. A task that reaches it stops with `stoppedBy: "budget"` and `limit: "maxCostUsd"`.
- `run_task` waits up to 90 seconds. A longer task keeps running. See [Limits](/concepts/limits).

## Why a task stops [#why-a-task-stops]

Every finished task has `ok` and `stoppedBy`. `ok` is `true` only when `stoppedBy` is `done`.

| `stoppedBy` | Meaning |
|---|---|
| `done` | The agent says it reached the goal. `answer` holds what it found |
| `blocked` | The agent could not go on: a navigation the guard refused, a site allowlist, or a rule of the mode held the step back. `reason` says which |
| `stuck` | The agent made no progress |
| `budget` | A limit was reached. `limit` is `maxSteps` or `maxCostUsd` |
| `captcha` | The page showed a CAPTCHA. webagent does not solve CAPTCHAs |
| `paused` | A person took over the session |
| `aborted` | The task was stopped on request, or its time limit ran out |
| `error` | Something failed inside the task. `reason` says what |
| `unanswered` | A question waited 10 minutes and got no answer |

`ok: false` is a normal result, not an HTTP error. Over MCP, `run_task` sets `isError` only when the agent could not test (`captcha`, `blocked`, `error`, `aborted`, `paused`, or a capacity or timeout stop). For a test, treat `done` as "the agent finished" and read `answer` to see whether the app behaved as expected. The agent decides when it is done. A task does not check assertions for you. For checks with a fixed pass or fail, use [`smoke_test`](/mcp/tools#smoke_test), which runs the `smoke-uat` [skill](/concepts/skills).

## What a task returns [#what-a-task-returns]

A task result has `ok`, `answer`, `stoppedBy`, `reason`, `limit`, `steps`, `costMicros` and `ms`. Each step lists its `op` (click, type, navigate and so on), whether it worked, how long it took, its cost and an error text. Costs are in millionths of a US dollar. A step has no screenshot or page URL of its own. A finished task can carry up to two screenshots: see [Task screenshots](#task-screenshots). See also [Evidence](/concepts/evidence).

While a task runs, the stored record has `status: "running"`. When it ends, it is `finished`.

## Task screenshots [#task-screenshots]

After a goal task ends, webagent keeps a screenshot of the last page, and of the page at the first step that failed. A task has at most two. A task that kept none has no `screenshots` field. A screenshot problem never fails the task.

A stored task (`GET /v1/sessions/:id/tasks`, `GET /v1/tasks`, the `get_task` MCP tool) lists them in `screenshots`:

```json title="screenshots (trimmed)"
"screenshots": [
  { "kind": "final", "url": "https://...", "expiresAt": "2026-11-13T00:05:00.000Z" },
  { "kind": "failed_step", "stepIndex": 3, "url": "https://...", "expiresAt": "2026-11-13T00:05:00.000Z" }
]
```

| Field | Meaning |
|---|---|
| `kind` | `final` is the page when the task ended. `failed_step` is the page at the first failed step |
| `stepIndex` | `failed_step` only: the position of that step, counted from 0 |
| `url` | A signed link. It opens without an API key |
| `expiresAt` | When the link stops working. It is short-lived (about 5 minutes today). Read the task again for new links |

`get_task` prints them as text too: `Screenshot (final state, link expires <time>): <url>` and `Screenshot of failed step <n>: <url>`. The `run_task` summary has no screenshot line: read the task with `get_task` after it ends. Screenshots are kept for tasks that ran after this feature was added, so older tasks have none.

## The task report [#the-task-report]

`get_report` with a task id (`tsk_…`), or `GET /v1/tasks/:id/report.json`, returns the same [report](/qa-testing/reading-results#the-test-report) as a smoke test: a verdict, the steps, and the console errors and failed network calls that happened while the task ran. The verdict is `pass` when the agent says it is done, `error` when it stopped for a reason that means it could not test, and `fail` for the other stops (`stuck`, `budget`, `unanswered`). The report says in `notes` that a task has no assertions. A task step in the report has only the action and its target. A task report has no findings. It carries the [task screenshots](#task-screenshots): the failed step has a `screenshotUrl`, and `evidence.finalScreenshotUrl` is the last page. Both stop working at `evidence.urlsExpireAt`.

Console errors and failed network calls come from the session log, which is saved when the session ends. Read the report again after the session has ended.
