Cadence
Reference

Leases

Observe and control the running work a pool has leased out.

When a pool staffs a stage, it leases a task to a worker; that lease is the unit of running work. A lease answers for a subject — most often a task, but a lease minted on a schedule (see Scheduled rules) can answer for a whole workflow or a whole space, with no task at all. These surfaces let you, the operator, watch and control leases whatever their subject.

Over the API, listing leases, reading one, reading its runtime coordinates, and cancelling one are operator-only: a lease's own token is refused there with 403 and lease_token_mismatch. Over MCP a worker can list and read leases with leases_list and leases_get, but only the leases whose subject its scope covers; cancelling stays operator-only on both surfaces. Reading a lease's runtime coordinates has no MCP tool — it is available over the API only. Reading a lease's logs and attachments is open to anyone who can see the lease, the lease itself included.

Listing and reading leases needs read; cancelling one needs member. See Authentication. Replace https://cadence.example.com with your instance's address.

Lease states

A lease is in one of these states. The active ones are pending, dispatching, dispatched, running, paused, and cancelling. The terminal ones are completed, failed, cancelled, lost, and killed.

How a queued lease reads on its board card

A lease that has not started running yet — pending, dispatching, or dispatched — shows a chip on its task's card in the board view (the web interface). That chip no longer collapses the whole queued family to one word: it names the real condition the lease is waiting on, so you can read why a lease is queued without opening it. The chip leads with the pool's name and follows it with the condition in brackets — for example, Delivery workers (pool full).

The condition is one of:

ChipWhat it means
(pool full)The pool is at its size — every slot is running or booting. Frees as its leases finish.
(space full)The space has no free vCPU for this lease's whole size. Frees as running work in the space finishes.
(instance full)The instance has no free vCPU for this lease's whole size. Frees as running work across the instance finishes.
(pool paused)The pool is paused. Nothing dispatches from it until you resume it.
(space archived)The space is archived. Nothing dispatches until you unarchive it.
(runtime refusing)The runtime is refusing to bring up a container.
(token pool unreachable)The pool's credential source cannot be reached, so no container can be started with it.
(awaiting agent)The container is up and the agent has not claimed the lease yet.
(starting)A slot is held and the container is being brought up.
(waiting until HH:MM)The lease deferred and will retry at the time shown.

The chip's colour and motion tell the two kinds of wait apart at a glance:

  • Amber and still means the lease needs a person. A paused pool to resume, an archived space to unarchive, the runtime refusing containers, or an unreachable credential source will not clear on their own — (pool paused), (space archived), (runtime refusing), and (token pool unreachable) read this way.
  • Neutral and spinning means the lease is working and waiting, and will move on its own. A ceiling that frees as siblings finish, a container booting, an agent about to claim, or a deferred wake read this way — (pool full), (space full), (instance full), (awaiting agent), (starting), and (waiting until HH:MM).

Under reduced-motion settings the spin is suppressed, but the colour and the still dot still read. A running, paused, or cancelling lease keeps the chip it has always had.

List leases

GET /api/v1/leases; MCP leases_list. Scope the list to a space — over the API with ?space=<key>, over MCP with space_key. Without a space, the API refuses with 422 and missing_scope (space is required).

Filter by state and cap with limit (up to 100 over the API; over MCP 50 by default, with an advertised maximum of 200; newest first). Over the API you can also page with cursor; over MCP the list comes back as a single page with no cursor. Each lease carries its id, state, attempt, pool, and subject_kind. Over MCP each lease additionally carries a subject reference to what it answers for, which the API does not; the API instead carries a workflow field, an object holding the workflow's slug. The API list also includes timing and the lease's worker version, both of which the MCP list omits. task is null on a workflow- or space-subject lease, so such a lease lists rather than failing. Over the API, workflow is set on a task-subject lease, where it is the workflow the task was on when the lease was created, and on a workflow-subject lease, and is null only on a space-subject lease. It does not follow a task moved to another workflow afterwards. The list is scoped by each lease's own space, so workflow- and space-subject leases appear alongside task leases.

curl "https://cadence.example.com/api/v1/leases?space=OPS&state=running" \
  -H "Authorization: Bearer smc_your_token_here"

Read one lease

GET /api/v1/leases/:id; MCP leases_get. Both return the lease's state, attempt, timing, pool, and subject_kind. The API response also includes the lease's worker version and a workflow field, both of which the MCP result omits. workflow is an object holding the workflow's slug — on a task-subject lease, the workflow the task was on when the lease was created, which does not change if the task later moves to another workflow; the workflow itself on a workflow-subject lease — and is null on a space-subject lease. The MCP result instead carries a subject reference the API does not. task is present on both surfaces but null on a workflow- or space-subject lease, so such a lease reads rather than failing. subject_kind is one of task, workflow, or space. An unknown lease returns 404 and lease_not_found over the API, or unknown lease id over MCP.

GET /api/v1/leases/:id/exec_target returns the runtime coordinates for reaching a running lease. It carries no payload, environment, or secrets.

Cancel a lease

POST /api/v1/leases/:id/cancel; MCP leases_cancel. A running or paused lease moves to cancelling while the worker is asked to stop; a lease still queued is cancelled at once. Cancelling an already-terminal lease is a no-op.

Read a worker's logs

GET /api/v1/leases/:id/logs; MCP leases_fetch_logs. Anyone who can see the lease can read its logs, whether it is still running or finished. Pass container to pick a container, tail to cap the number of lines, since for an ISO-8601 lower bound, and cursor to page.

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

When the pool's runtime keeps no logs, the API returns 501 with unsupported_runtime; over MCP the same case comes back as an invalid-arguments error.

Read a lease's attachments

GET /api/v1/leases/:id/attachments and .../attachments/:attachment_id; MCP leases_list_attachments. Listing returns each attachment's metadata — id, kind, filename, content_type, byte_size, and created_at; the MCP tool adds a download_path for each, which the API response does not. Fetching one by id streams its bytes. A worker uploads its own attachments; that upload is not an operator surface.

An old lease's detail is reclaimed

After a retention window, Cadence reclaims the detail of a finished lease to recover storage (see An old lease's detail is reclaimed for what it clears and what it keeps). This changes what a couple of these surfaces return for such a lease:

  • Read a lease's attachments returns an empty list — the sweep purges a reclaimed lease's attachments.
  • The lease still lists and reads: its state, attempt, timing, pool, and subject_kind are kept, so leases_list and leases_get resolve as they always do — a reclaimed lease is not missing.
  • Its activity timeline is left intact, including the entry recording how the lease ended, so the account of what the lease did survives on the task even after its detail is reclaimed.

What a worker reads from its lease

This section is for the worker running under a lease, reading its own payload — not for the operator. Over MCP, under its lease token, a worker calls lease_fetch_payload to get the bundle it works from. What the bundle carries depends on the lease's subject.

The subject context

  • A task subject carries the task's fields — its key, title, body, properties, dependencies, the summaries of prior attempts, and the task's recent activity.

  • A workflow subject carries no task fields. In their place it carries a subject block and the workflow's own recent activity:

    "subject": { "kind": "workflow", "slug": "nightly-sweep", "name": "Nightly sweep", "description": "…" }
  • A space subject likewise carries a subject block — with the space's key and name, and no slug or description — and the space's recent activity:

    "subject": { "kind": "space", "key": "OPS", "name": "Operations" }

A workflow- or space-subject lease has no task, no dependencies, and no prior task summaries: there is no task to carry them.

The trigger

A lease minted by an inbound rule additionally carries a trigger block naming the event that started it:

"trigger": {
  "topic": "email.received",
  "occurred_at": "2026-09-11T13:59:00Z",
  "data": { "from": "…", "subject": "…", "body": "…", "attachments": [ … ] }
}

trigger.data is the event's whole data bag — for an email, the sender, recipient, subject, body, and attachment list described under the email.received event. The trigger block is absent on a lease minted any other way — a lease from a stage entry or from a scheduled rule carries no trigger.

What an agent reads about its model

A lease run by an agent pool reads kind: "agent" and the pinned agent version's model. When the version sets an effort, the payload carries it too:

"kind": "agent",
"model": "claude-sonnet-5",
"effort": "medium"

When the version sets no effort, the payload has no effort key at all; a worker that finds none should leave the model at its own default. Cadence only hands the value over: what the worker does with it is up to the worker's image.

What a classifier reads

A lease run by a classifier pool carries a payload body of its own, alongside the subject context above. It reads kind: "classifier" and the pinned classifier version's input document, copied through verbatim:

"kind": "classifier",
"input": {
  "attachments": [ { "name": "screenshot.png" } ],
  "questions": [ … ]
}

Cadence copies the input document through untouched — it renders nothing, interpolates nothing, and does not inspect a question. A classifier payload carries none of the LLM fields, skills, or MCP configuration an agent lease carries. The worker composes its request to the question-answering provider from the task body in the subject context, the task attachments named in input.attachments, and the questions list.

The worker ends the lease by reporting its answers as the details of its completion — a JSON object, one field per answer — with cadence worker complete --outcome success --details <json> (equivalently the details object on POST /api/v1/leases/:id/complete). What that reported result then does to the task — the checks and properties it sets — is decided by the version's output document, which the worker never sees: its expressions render over the reported result, so the field names the worker reports are the names those expressions read. Cadence applies the output when the lease reports success; see How an output expression is rendered.

On this page