Cadence
Guides

Read what a worker did

After a lease has run, read what the worker did — its logs, the resources it used, and the task's timeline.

A pool leases a task to a worker, the worker runs, and the lease ends. Afterwards you often want to know what the worker actually did: what it printed, what it consumed, and what it changed on the task. This guide reads all three, in order — the lease's logs, its usage, and the task's timeline.

You do this over the Model Context Protocol endpoint. Each step names its own tool, and where the browser shows the same thing a different way, that is noted at the step. For the exhaustive surfaces behind this guide, see Leases, Usage and time logs, and the task activity feed.

Before you start

Reading a lease, its logs, its usage, and a task's timeline all need read on the space. See Authentication. This guide is written for you, an operator, over MCP; it uses the example task key OPS-42 and the example space key OPS.

You reach each of these three surfaces by a different handle: the logs and usage by the lease's numeric id, and the timeline by the task key. So the first step is to find the lease.

1. Find the lease

List the space's leases with leases_list. Pass space_key, and narrow with state — completed, failed, cancelled, lost, or killed for a lease that has finished. The list is newest-first.

// leases_list
{ "space_key": "OPS", "state": "completed" }

Each row carries the lease's id, state, attempt, pool, subject_kind, and the task it answers for:

{
  "leases": [
    { "id": 5821, "state": "completed", "attempt": 1, "pool": { "id": 12, "name": "Delivery workers" }, "subject_kind": "task", "task": { "key": "OPS-42" } }
  ]
}

Take the id — 5821 here — for the next two steps. A lease that ran against a whole workflow or space rather than a task lists with a null task; it still has an id and logs and usage of its own.

2. Read its logs

Read a page of the worker's output with leases_fetch_logs. Pass the lease id. Anyone who can see the lease can read its logs, whether it is still running or has finished.

// leases_fetch_logs
{ "id": 5821 }
{
  "events": [
    { "timestamp": "2026-05-01T10:00:00Z", "container": "agent", "stream": "stdout", "message": "…" }
  ],
  "truncated": false,
  "next_cursor": "…"
}

The logs default to the agent container. To read a sidecar instead, pass container. Cap the page with tail, set an ISO-8601 lower bound with since, and follow next_cursor with cursor to read the next page.

Not every pool's runtime keeps logs. When this one does not, the call comes back as an invalid-arguments error rather than an empty page — that is the runtime not storing logs, not a lease that ran silently.

3. Read its usage

Read what the lease consumed with lease_usages_list. Pass the lease id as lease:

// lease_usages_list
{ "lease": 5821 }

Each raw row carries lease_id, counter, amount, unit, reported_at, and idempotency_key. To sum the counters instead of listing every row, pass group_by — a comma-separated subset of counter, pool, worker_version, task_type, image, and day:

// lease_usages_list
{ "lease": 5821, "group_by": "counter" }

To compare a lease against the rest of the space, scope the query to the space instead of the lease — pass space in place of lease, and the same filters and group_by apply across every lease in it. See Lease usage for the full filter set.

4. Read the task's timeline

The logs tell you what the worker printed and the usage tells you what it consumed; the timeline tells you what happened to the task — including how the lease ended. Read it with activities_list. Pass the task_key:

// activities_list
{ "task_key": "OPS-42" }

Entries come back newest-first; pass order: "asc" for oldest-first, limit (up to 200) to cap the page, and since_id to read only entries after one you have already seen. Each entry carries its id, kind, author, payload, and created_at.

The timeline is where a lease accounts for itself. When a lease finishes it records an entry naming its outcome and a short summary, so you can read that a worker completed, failed, or was cancelled without reading its logs. If the lease never started — held behind a full pool, a space or instance with no free vCPU, a paused pool, or an archived space — the timeline carries the wait instead, naming the condition (see What moves a task without a person).

The task's timeline outlives the lease's own detail. After a retention window Cadence reclaims an old lease's bulky detail — and its attachments go with it — but the task's timeline, including the entry recording how the lease ended, is kept. So the account of what a worker did survives on the task even once the lease itself is reclaimed (see An old lease's detail is reclaimed).

In the browser

Each of these three reads has a place in the web interface too, and you reach them from the workflow's board view rather than by a lease id:

  • A running or finished lease shows on its task's card, and while it is queued the card chip names why it is waiting (see how a queued lease reads on its board card).
  • The task drawer carries the timeline, where the lease's outcome and the task's other activity read in one place.

The logs and the cross-lease usage totals are the reads you go to MCP for; the board view is where you go to see a lease in the context of the task it ran against.

On this page