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.
Take work in with an inbound webhook
Register a webhook token, point an inbound rule at the receiver, and turn an outside delivery into a task.
Export a space
Take a portable JSON reference of a space's workflow configuration with the space_export MCP tool, then replicate the space by re-issuing the normal writes — there is no machine import.