Skip to content

Tasks API

Task reads (list, detail, tree, bulk-delete) live under /projects/{slug}/tasks. Mutating actions (retry, cancel, bulk-retry, purge a queue, plus worker control) go through /projects/{slug}/commands so the brain can mint an audit-chained command record and dispatch it to the responsible agent.

GET /api/v1/projects/{slug}/tasks

Role: viewer.

Query paramTypeNotes
statestringOne of received, started, succeeded, failed, cancelled, retried, lost.
prioritystringComma-separated, e.g. critical,high.
namestringExact match on task name.
searchstringFull-text across name, queue, worker.
queuestringExact match.
workerstringExact match on worker_name.
since / untilRFC 3339Bound on received_at.
cursoropaquePagination cursor from the prior page.
limitint1..5000. Default from server settings.
formatstringcsv, xlsx, or json. Non-JSON overrides pagination and streams the full result.
fieldsstringComma-separated projection for export.

Response (JSON mode):

{
"items": [
{
"id": "01H...",
"project_id": "...",
"engine": "celery",
"task_id": "9d2c...",
"name": "email.send",
"queue": "default",
"state": "failed",
"priority": "normal",
"args": ["<redacted>"],
"kwargs": {"to": "<email>"},
"result": null,
"exception": "ValueError: ...",
"traceback": "...",
"retry_count": 0,
"eta": null,
"received_at": "...",
"started_at": "...",
"finished_at": "...",
"runtime_ms": 142,
"worker_name": "worker-1@host",
"parent_task_id": null,
"root_task_id": null,
"tags": [],
"created_at": "...",
"updated_at": "..."
}
],
"next_cursor": "..."
}
GET /api/v1/projects/{slug}/tasks/{engine}/{task_id}

Role: viewer. Same TaskPublic shape as the list endpoint.

GET /api/v1/projects/{slug}/tasks/{engine}/{task_id}/tree

Role: viewer. Walks to the task’s root via root_task_id (or treats the task itself as root if the field is null) and returns every task in the project sharing that root. Capped at 500 nodes; the response carries truncated: true when the cap kicks in.

POST /api/v1/projects/{slug}/tasks/bulk-delete

Role: admin. CSRF-protected. Throttled by a per-route bulk-action limiter.

{
"task_ids": ["..."],
"filter_state": "failed",
"filter_name": "email.send",
"filter_queue": "default",
"filter_since": "2026-04-16T00:00:00Z",
"filter_until": "2026-04-16T23:59:59Z"
}

task_ids is capped at 1000 entries. The handler scopes every delete to the project regardless of any body field. Returns {"deleted_count": N}.

Commands (retry, cancel, bulk-retry, purge-queue)

Section titled “Commands (retry, cancel, bulk-retry, purge-queue)”

Every action that needs an agent round-trip is issued as a command. The brain inserts a row in commands, signs it, and pushes it over the agent’s WebSocket; the agent runs the action and POSTs the result back, which the brain records as the command outcome.

GET /api/v1/projects/{slug}/commands?status=&cursor=&limit=

Role: viewer. status is one of issued, dispatched, succeeded, failed, timed_out.

GET /api/v1/projects/{slug}/commands/{command_id}

Role: viewer.

POST /api/v1/projects/{slug}/commands/retry-task

Role: operator.

{
"agent_id": "...",
"engine": "celery",
"task_id": "9d2c...",
"idempotency_key": "optional-string",
"override_kwargs": {"foo": "bar"}
}

override_kwargs is capped at 64 KiB JSON.

POST /api/v1/projects/{slug}/commands/cancel-task

Role: operator.

{
"agent_id": "...",
"engine": "celery",
"task_id": "9d2c...",
"idempotency_key": "optional-string"
}
POST /api/v1/projects/{slug}/commands/bulk-retry

Role: operator.

{
"agent_id": "...",
"filter": {"state": "failed", "queue": "default", "name": "email.send"},
"max": 1000,
"idempotency_key": "optional-string"
}

max is bounded 1..10000.

POST /api/v1/projects/{slug}/commands/purge-queue

Role: admin.

{
"agent_id": "...",
"queue": "default",
"confirm_token": "<hmac of (queue_name, observed_depth)>",
"force": false,
"idempotency_key": "optional-string"
}

Either confirm_token (computed from the current queue depth via the engine adapter’s expected_confirm_token helper) or force=true (logged at CRITICAL on the agent) is required.

The same /commands router exposes five worker-control verbs the dashboard uses to manage running workers without touching the application code. Each command is signed, audit-logged, and dispatched to the named agent over the WebSocket.

POST /api/v1/projects/{slug}/commands/restart-worker

Role: admin.

{
"agent_id": "...",
"worker_name": "celery@worker-1",
"idempotency_key": "optional-string"
}

The agent sends a graceful restart signal to the named worker. The host process is unaffected; only the worker’s adapter state is recycled.

POST /api/v1/projects/{slug}/commands/pool-resize

Role: admin.

{
"agent_id": "...",
"worker_name": "celery@worker-1",
"delta": 2,
"idempotency_key": "optional-string"
}

delta is bounded -100..100. Positive grows the pool, negative shrinks it. The agent’s engine adapter translates the delta into the engine-native call (Celery’s pool_grow / pool_shrink, etc.). Workers that do not support pool resize return ok: false on the resulting command_result.

POST /api/v1/projects/{slug}/commands/add-consumer

Role: admin.

{
"agent_id": "...",
"worker_name": "celery@worker-1",
"queue": "billing",
"idempotency_key": "optional-string"
}

Tells the worker to start consuming from the named queue.

POST /api/v1/projects/{slug}/commands/cancel-consumer

Role: admin. Same body shape as add-consumer. The worker stops consuming from queue but keeps running on its remaining queues.

POST /api/v1/projects/{slug}/commands/rate-limit

Role: admin.

{
"agent_id": "...",
"task_name": "myapp.tasks.send_email",
"rate": "100/m",
"worker_name": "celery@worker-1",
"idempotency_key": "optional-string"
}

rate follows Celery’s grammar: integer optionally suffixed with /s, /m, or /h; "0" clears the limit. The pattern is enforced server-side so an obvious typo is rejected before the command row is minted. worker_name is optional: an omitted or empty value broadcasts the new rate to every worker subscribed to the broker. The agent-side action logs at CRITICAL when this global-throttle path fires, and the audit row carries the same flag.

Every worker-control command requires an agent_id, which the agents API returns from its list endpoint. Use the agents list to discover the right id; the worker_name field references the engine-native worker identifier (e.g. Celery’s worker@host string), which the workers list under agents surfaces alongside the agent.